Le routage avec React Router DOM
Navigation en single page
L’un des atouts majeurs des bibliothèques et frameworks frontend est la possibilité de monter une application entière qui s’exécute à travers une seule page. C’est ce qui est connu sous le nom de
Single Page Application (ou SPA).
Dans ce genre d’applications, le fait de cliquer sur une lien (ou de poster un formulaire) ne recharge pas la page entièrement, mais rafraîchit seulement les parties concernées en mode non bloquant. Cela revient à la même chose que d’utiliser
l’objet XMLHttpRequest ou
l’API Fetch, mais à plus grande échelle.
En React, il existe une bibliothèque particulièrement puissante qui permet de donner vie à la navigation en Single Page, il s’agit de
React Router DOM.
Bibliothèque React Router DOM de React
Afin de pouvoir utiliser la bibliothèque React Router DOM dans un projet React, il faut d’abord l’installer à travers le terminal en tapant cette commande :
npm install react-router-dom
La bibliothèque React Router DOM inclut plusieurs composants essentiels au routage (redirection entre les ressources de l'application). Ces modules sont:
- BrowserRouter: Il s'agit d'un composant de type wrapper, c'est à dire qui enveloppe l'application (ou la partie de l'application) où on veut mettre en place le routage.
- Routes: Il s'agit également d'un composant de type wrapper et qui permet d'envelopper les routes qui seront spécifiées avec le composant <Route>.
- Route: C'est le composant qui définit la route, c'est à dire la ressource qui sera affichée dans la zone enveloppée par le composant <Routes>.
- Link: Il s'agit du composant qui permet de mettre en place les liens de navigation qui permettent de naviguer entre les pages en SPA (sans recharger la page).
Le fait d'utiliser la balise <a> à la place du composant <Link> créera des liens hypertextes classiques qui engendrent un rechargement complet de la page.
Le code suivant illustre un exemple de routage de base:
import {BrowserRouter, Routes, Route, Link} from 'react-router-dom'
import Home from './components/Home'
import Contact from './components/Contact'
function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">Page d'accueil</Link>
<Link to="/contact">Page de contact</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</BrowserRouter>
);
}
Le composant
<Link> crée un lien de navigation cliquable. D'ailleurs, le fait d'inspecter le code sur le navigateur après exécution montre que ce qui a été généré c'est un lien hypertexte avec la balise
<a>, sauf que ce lien est associé à un événement Javascript qui actionnera le processus de navigation sans rechargement de la page.
L'attribut
to permet de spécifier le chemin qui doit être passé en guise d'URL. Dans ce cas, nous avons deux chemins, à savoir
/ et
/contact. Cela dit qu'il faut créer deux
composants indépendants que l'on importe et qui seront affichés selon le lien cliqué.
La zone qui sera rafraichie si on clique sur un lien est enveloppée par le composant
<Routes>. Dedans, on a placé deux routes à l'aide du composant
<Route>. Chaque route dispose d'un attribut
path qui indique le chemin (URL) qui doit être activé et un attribut
element qui accueille le nom du composant qui sera chargé selon le chemin activé.
Remarquez que le composant a été placé dans une interpolation JSX. D'ailleurs, on peut même passer des
props au composant afin de personnaliser son affichage. On peut également
conditionner l'affichage des composants à l'aide de l'opérateur ternaire.
Notez que tous les composants liés au routage (<Routes>, <Route> et <Link>) doivent être enveloppées par <BrowserRouter>.
Concernant les composant
<Home /> et
<Contact />, on peut y placer ce qu'on veut. Par exemple, je me contenterai d'y placer des titre
H1 comme ceci:
Code source de
./components/Home.js
function Home(){
return (
<h1>Page d'accueil</h1>
)
}
export default Home
Code source de
./components/Contact.js
function Contact(){
return (
<h1>Page de contact</h1>
)
}
export default Contact
Le hook useParams
Il est possible de spécifier des paramètres dynamiques lors du routage. C'est à dire, envoyer des paramètres au composant appelé lors de la spécification d'une route. C'est comme si on envoyait des paramètres à travers l'URL en utilisant la méthode GET supportée par les formulaires HTML.
Pour spécifier un paramètre dans une route, on le place après un slash et on le prefixe par deux points. Par exemple:
<Route path="/produit/:id" element={<Produit />} />
Dans le lien de navigation, on exprime par exemple le produit identifié par 123 comme ceci:
<Link to="/produit/123">Détails du produit</Link>
On peut aussi spécifier directement ce lien dans l'URL comme ceci:
http://localhost:3000/produit/123
Pour récupérer l'identification du produit dans le composant qui implémente ce dernier (
./components/Produit.js) on aura par exemple un code qui ressemble à ceci:
import { useParams } from 'react-router-dom'
function Produit(){
const { id } = useParams()
return (
<h1>Détails du produit {id}</h1>
)
export default Produit
}
Il faut commencer par importer le module
useParams de la bibliothèque
react-router-dom. Ensuite, dans la partie consacrée à la logique du composant, on va simplement invoquer le hook
useParams(). Le hook useParams() retourne un objet Javascript donc les clés sont ce qu'on a spécifié dans la route et qui est préfixé par deux point (
id dans notre cas), et la valeur est ce qu'on a passé à travers le lien (ou l'URL), ce qui correspond à 123 dans l'exemple.
Notez qu'on a opté pour la technique de déstructuration qui consiste à verser le contenu du dictionnaire des des variables ordinaires (comme on l'a fait pour le
hook useState).
Il est possible de passer des paramètres multiples dans la route. Par exemple, on spécifie le produit identifié par
123 et qui appartient à la catégorie
imprimante comme ceci:
<Route path="/produit/:id/:categorie>" element={<Produit />} />
Le lien de navigation ressemblera à ceci:
<Link to="/produit/123/imprimante">
Détails du produit
</Link>
La récupération des paramètres dans le composant aura cette forme:
const { id , categorie } = useParams()