Una ruta és un "mapping" entre una URL i un component
Introducció
React Router és una biblioteca que et permet crear rutes.
Una ruta és un "mapping" entre el path d'una URL i un component:
flowchart LR Path --route--> Component
Aquest tipus de navegació s'anomena "client-site routing" perquè el navegador no mostra pàgines generades des del servidor, sinó que estat navegant d'un component a l'altre dins de l'aplicació.
En aquest enllaç tens el projecte de suport: https://gitlab.com/xtec/typescript/react-router
Entorn de treball
Crea un projecte
$ bun create vite react-router --template react-swc-ts
$ bun install react-bootstrap bootstrap
Instal.la la biblioteca react-router-dom
:
$ bun install react-router-dom
Observació. Utilitzem la versió v6 !
Route
Modifica el fitxer App.tsx
.
A continuació tens dues rutes: /
i /student
:
import {BrowserRouter, Routes, Route } from "react-router-dom"
export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/student" element={<Student/>} />
</Routes>
</BrowserRouter>
)
}
function Home() {
return <h1>Home</h1>
}
function Student() {
return <h1>Student</h1>
}
Pots verificar que:
URL | Path | Component |
---|---|---|
http://localhost:5173/ | / |
<Home/> |
http://localhost:5173/student | /student |
<Student/> |
Segment dinamic
Si vols pots utilitzar parametres al path.
Crea el fitxer data.ts
amb alguns estudiants:
export type Student = {
id: number
name: string
surname: string
}
export const students: Student[] = [
{ id: 1, name: "Mary", surname: "Sinclair" },
{ id: 3, name: "Olivia", surname: "Hart" }
]
El component <Student/>
pot utilitzar aquest parametres mitjançant el hook useParams
:
import { BrowserRouter, Routes, Route, useParams } from "react-router-dom"
import {students} from "./data"
export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/student/:id" element={<Student />} />
</Routes>
</BrowserRouter>
)
}
function Student() {
const { id } = useParams()
const student = students.find(student => student.id == Number(id))
if (student == null) {
return <p>Student not found!</p>
}
return <p>{student.name} {student.surname}</p>
}
Pots veure que ara React respon a http://localhost:5173/student/1 amb el nom de l'estudiant.
Link
Pots crear enllaços amb <a>
.
Quan l'usuari fa clic a l'enllaç, l'usuari navega al path que s'ha especificat dins el component <route>
i es renderitza el component que fa "match".
A continuació crea un component <Students>
que mostra una llista de tots els estudiants amb un enllaç a cada estudiant:
import { BrowserRouter, Routes, Route, useParams } from "react-router-dom"
import { students } from "./data"
export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home/>}/>
<Route path="/student/" element={<Students />} />
<Route path="/student/:id" element={<Student />} />
</Routes>
</BrowserRouter>
)
}
function Students() {
return (
<div className="container">
<h3>Students</h3>
<table className="table">
<tr><th>Surname</th><th>Name</th></tr>
{students.map(student => (
<tr>
<td><a href={"/student/" + student.id}>{student.surname}</a></td>
<td>{student.name}</td>
</tr>)
)}
</table>
</div>
)
}
Separació per pàgines.
Quan el projecte creix en components i en desenvolupadors, és bona idea separar cada ruta en una pàgina apart en format .tsx
; aixi com crear components comuns a diverses pàgines (o a la pàgina principal) com és el cas del Menu.
Suposem que volem crear una nova ruta que apunti a la pàgina pages/Teachers.tsx
.
El component Teachers
d'aquesta pàgina tindrà el següent codi, que inclou el nom i les fotos:
import "bootstrap/dist/css/bootstrap.min.css";
const people = [
{ name: "Anna López", avatar: "https://i.pravatar.cc/100?img=1" },
{ name: "Joan Díaz", avatar: "https://i.pravatar.cc/100?img=7" },
{ name: "Marta Juárez", avatar: "https://i.pravatar.cc/100?img=10" },
{ name: "Pau Moretti", avatar: "https://i.pravatar.cc/100?img=11" },
{ name: "Laia Soler", avatar: "https://i.pravatar.cc/100?img=5" },
{ name: "Marc Simon", avatar: "https://i.pravatar.cc/100?img=8" },
];
export default function Teachers() {
return (
<div className="container py-4">
<h2 className="text-center mb-4">Professorat</h2>
// ...
</div>
);
};
Per a separar i reutilitzar el component Menu
crearem la pàgina pages/Menu.tsx
.
import Container from 'react-bootstrap/Container';
import Nav from 'react-bootstrap/Nav';
import Navbar from 'react-bootstrap/Navbar';
export default function Menu() {
return <Navbar bg="primary" data-bs-theme="dark">
<Container>
<Navbar.Brand href="/">School</Navbar.Brand>
<Nav className="me-auto">
<Nav.Link href="/">Home</Nav.Link>
<Nav.Link href="/student/">Students</Nav.Link>
<Nav.Link href="/teachers/">Teachers</Nav.Link>
</Nav>
</Container>
</Navbar>
}
Finalment, hem d'editar el component principal App.tsx
; només mostrarem les capçaleres amb els imports i el component principal App
.
import { BrowserRouter, Routes, Route, useParams } from "react-router-dom"
import { students } from "./data"
import Teachers from './pages/Teachers';
import Menu from './pages/Menu';
export default function App() {
return (
<BrowserRouter>
<Menu />
<Routes>
<Route path="*" element={<NotFound />} />
<Route path="/" element={<Home />} />
<Route path="/teachers" element={<Teachers />} />
<Route path="/student/" element={<Students />} />
<Route path="/student/:id" element={<Student />} />
</Routes>
</BrowserRouter>
)
}
function NotFound() {
return (
<>
<p className="text-danger fs-4">404 Not Found</p>
</>
)
}
function Home() {
return (
<>
<p>Escola Patufet</p>
</>
)
}
Activitat
1.- Crea una barra de navegació compartida per totes les "pagines".
// ...
import Container from 'react-bootstrap/Container';
import Nav from 'react-bootstrap/Nav';
import Navbar from 'react-bootstrap/Navbar';
// ...
function Menu() {
return <Navbar bg="primary" data-bs-theme="dark">
<Container>
<Navbar.Brand href="/">School</Navbar.Brand>
<Nav className="me-auto">
<Nav.Link href="/">Home</Nav.Link>
<Nav.Link href="/student/">Students</Nav.Link>
</Nav>
</Container>
</Navbar>
}
function Home() {
return (
<>
<Menu />
<p>Escola Patufet</p>
</>
)
}
// ...
2.- Afegeix una ruta "Not Found"
export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path="*" element={<NotFound />} />
<Route path="/" element={<Home />} />
// ..
3.- Fes els exemples de https://www.freecodecamp.org/news/use-dynamic-segments-in-react-router/