Saltar al contingut

Router

React Router et permet renderitzar un component concret en funció del "path" de la url i navegar entre components.

React Router et permet renderitzar un component concret en funció del “path” de la url.

Això s’aconsegueix creant un conjunt de rutes, on cada ruta és un “mapping” entre el path d’una URL i un component:

route

Path

Component

Crea un projecte amb Bun

Terminal window
bun create vite router --template react-swc-ts
cd router
bun update

Instal·la la biblioteca react-router:

Terminal window
bun add react-router
bun add -d @types/react-router

Imagina que tens un component Student (modifica el fitxer App.tsx).

export default function App() {
return <Student/>
}
function Student() {
return <h1>Student</h1>
}

Inicia Vite:

Terminal window
bun run dev

Si obres el navegador al path / http://localhost:5173/ es renderitzarà el component Student.

El curiós és que si obres el navegador al path /hello http://localhost:5173/student també es renderitzarà el component Student

El que faràs a continuació és que el component App en lloc de retornar el component Student retorni el component BrowserRouter.

import {BrowserRouter, Routes} from "react-router"
export default function App() {
return (
<BrowserRouter>
<Routes>
</Routes>
</BrowserRouter>)
}

Com no has definit cap ruta, el component BrowserRouter retorna un contingut buit pel path /: </>

Afegeix aquesta ruta a Routes: / -> <Student/>:

import {BrowserRouter, Routes, Route} from "react-router"
export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path={"/"} element={<Student/>}/>
</Routes>
</BrowserRouter>)
}

Ara, com el component BrowserRouter té definida una ruta pel path / que indica que ha de retornar el component Student, sí que es renderitza el component Student per a l’URL http://localhost:5173.

I a més, el component Student es renderitza únicament per aquest path a diferència del que passava al principi.

Modifica la ruta perquè el component Student es renderitzi al path /student.

Verifica que funciona: http://localhost:5173/student

Com pots intuir, dins del component Routes pots posar més components Route que apuntin al mateix o a altres components.

Crea un component Home, i afegeix una ruta de / a <Home/>:

La majoria dels components utilitzen props per crear el seu contingut.

Modifica el component Student perquè utilitzi la propietat name

function Student({name}: { name: string }) {
return <h1>Student: {name}</h1>
}

Ara la ruta /student donarà error perquè el component Student requereix com a paràmetre la propietat name.

Cap problema 🐱!

// ...
<Route path={"/student"} element={<Student name={"Laura"}/>}/>

Verifica que la ruta torna a funcionar: http://localhost:5173/student

El problema és que aquesta ruta només serveix per a Laura 👩‍🦰

El path d’una URL està format per segments que es divideixen amb /, i si un segment comença amb : es converteix en un “segment dinàmic”.

Per exemple, a /student/:name, /:name és un segment dinàmic.

S’anomena dinàmic perquè admet qualsevol valor i es proporciona al component com un paràmetre.

Modifica la ruta i elimina la prop name del component Student 😯

// ...
<Route path={"/student/:name"} element={<Student/>}/>
// ...
function Student() {
return (<h1>Student: Laura 👩‍🦰</h1>)
}

Verifica que el router funciona per a qualsevol path /student/:name com [http://localhost:5173/laura](http://localhost:5173/laura, http://localhost:5173/eva, etc…

… i que sempre renderitza el mateix estudiant “Laura 👩‍🦰”

Llavors, resulta que ara:

  • Tens configurat el component BrowserRouter amb un component Route .
  • Perquè retorni el component Student quan el path del navegador coincideixi amb /student/:name.
  • On :name pot ser el que l’usuari vulgui.

L’únic problema que has de resoldre és com pot el component Student accedir al paràmetre name?

Per això està la funció useParams():

function Student() {
const {name} = useParams()
return (<h1>Student: {name}</h1>)
}

I ara si vas a http://localhost:5173/eva la pàgina renderitza l’estudiant “eva 👩‍🦰”

Crea el fitxer data.ts amb alguns estudiants:

export type Student = {
id: number
emoji: string
name: string
surname: string
}
export const students: Student[] = [
{id: 1, emoji: "👩‍🦰", name: "Mary", surname: "Sinclair"},
{id: 2, emoji: "🧙‍♂️", name: "John", surname: "Smith"},
{id: 3, emoji: "🐱", name: "Olivia", surname: "Hart"}
]

Modifica la ruta de /student/:name a /student/:id per utilitzar l’id d’estudiant en lloc del name:

Modifica el component Student perquè busqui l’estudiant a la llista students de data.tsx:

Verifica que ara aquesta url http://localhost:5173/student/1 respon amb ”👩‍🦰 Mary Sinclair”

Afegeix una nova ruta:

export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path={"/"} element={<Home/>}/>
<Route path={"/student/"} element={<Students/>}/>
<Route path={"/student/:id"} element={<Student/>}/>
</Routes>
</BrowserRouter>)
}

Crea el component Students que retorni una taula amb tots els estudiants:

IDEmojiSurnameName
1👩‍🦰SinclairMary
2🧙‍♂️SmithJohn
3🐱HartOlivia

Una aplicació ha de tenir enllaços perquè l’usuari pugui navegar d’una pàgina a una altra pàgina.

Modifica el component Home i afegeix un enllaç normal a /students:

function Home() {
return <a href="/student/">Students</a></li>
}

Però a l’exemple li falta una mica d’estil 🧙‍♂️ 💫

function Home() {
return (
<div className={"container m-5"}>
<ul className="nav nav-underline mb-3 justify-content-center">
<li className="nav-item">
<a className="nav-link active" aria-current="page" href={"/"}>Home</a>
</li>
<li className="nav-item">
<a className="nav-link active" href={"/student/"}>Students</a>
</li>
</ul>
<h3>Patufet School</h3>
</div>
)

Quan l’usuari fa clic a l’enllaç, el servidor respon retornant una altra vegada tota l’aplicació, i com el path ha canviat BrowserRouter retorna el component corresponent.

De funcionar funciona, funciona bé de moment, però no és gens eficient 🤔!

React Router proporciona el component Link, que és un “wrapper” d’<a>, que el que fa és impedir que el navegador executi l’enllaç, i en el seu lloc li diu al BrowserRouter que actualitzi el contingut a la nova ruta.

D’aquesta manera, tot i que sembli que estem navegant de pàgina a pàgina, en realitat estem navegant de component a component 😀!

Modifica l’enllaç:

function Home() {
return (
// ...
<Link className="nav-link active" aria-current="page" to={"/"}>Home</Link>
}

Ves a l’inici (/), atura el servidor, i verifica que els enllaços funcionen!

Terminal window
19:09:29 [vite] (client) hmr update /src/App.tsx (x22)
error: script "dev" exited with code 58
PS C:\Users\david\react-router>

Aquest tipus de navegació s’anomena “client-site routing” perquè, tot i que el navegador mostri una url diferent, estàs navegant d’un component a un altre component dins de l’aplicació.

Torna a arrancar el servidor:

Terminal window
> bun run dev
...

A continuació modifica el component <Students> de manera que cada estudiant de la taula tingui un enllaç a la ruta <Route path={"/student/:id"} element={<Student/>}/>.

D’aquesta manera l’usuari pot fer clic i anar a la “pàgina” de l’estudiant:

Crea un component Navbar amb una barra de navegació de Bootstrap - Navbar:

Afegeix el component Navbar als components Home, Student i Students.

Com has vist, React et permet construir aplicacions client que no necessiten un servidor.

Obre el terminal i executa:

Terminal window
> bun run build
vite v6.0.3 building for production...
26 modules transformed.
dist/index.html 0.48 kB gzip: 0.32 kB
dist/assets/index-COkpbCJz.js 145.81 kB gzip: 47.24 kB
built in 707ms

Al directori dist hi ha tots els fitxers necessaris per executar l’aplicació.

A continuació pujaràs el contingut a un allotjament web:

  • Registra’t a Netlifly.
  • Crea un “new team” amb un pla gratuït:

Puja el directori dist que acabes de crear:

Ves a la pàgina del lloc (i canvia el nom si vols):

Hi apareix la URL del lloc accessible des de qualsevol navegador connectat a Internet!

Modifica el fitxer data.ts i afegeix uns quants professors a l’escola:

En el aparece la URL del sitio accesible desde cualquier navegador conectado a Internet!

Modifica el fichero data.ts y añade unos cuantos profesores a la escuela:

export type Teacher = {
id: string,
name: string,
avatar: string
}
export const teachers: Teacher[] = [
{id: "pmoretti", name: "Pau Moretti", avatar: "https://i.pravatar.cc/100?img=11"},
{id: "lsoler", name: "Laia Soler", avatar: "https://i.pravatar.cc/100?img=5"},
{id: "msimon", name: "Marc Simon", avatar: "https://i.pravatar.cc/100?img=8"},
]

Crea el fichero teachers.tsx con los componentes Teacher y Teachers:

Añade las rutas /teacher/ y /teacher/:id al componete BrowserRouter.

Añade una ruta “Not Found”

export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path="*" element={<NotFound/>}/>
<Route path="/" element={<Home/>}/>
// ..
}
function NotFound() {
return (
<>
<p className="text-danger fs-4">404 Not Found</p>
</>
)
}

Añade alguna mejoras, por ejemplo:

  • Una pàgina con un mapa de donde está la escuela.
  • etc.

Despliega la nueva version en Netlify.


El contingut d'aquest lloc web té llicència CC BY-NC-ND 4.0.

©2022-2025 xtec.dev