Par défaut, les applications React ne contiennent qu'une seule page HTML : le public/index.html
. Comment faire si vous programmez un blog avec React contenant une multitude de posts différents ? Vous devez le chargement de chaque post depuis React.
C'est précisément le rôle de la librairie [react-router](https://reactrouter.com/)
.
Concrètement, cette librairie permet à l'utilisateur de naviguer entre les différentes parties d'une application en entrant une URL ou en cliquant sur un élément.
Pour l'installer, vous devrez exécuter la commande suivante dans votre terminal : yarn add react-router-dom
Démarrons par le squelette d'une application. Cette application contient trois pages : Home, About et Contact. Ces trois pages sont toutes visibles au chargement de notre application.
import React from "react";
import "./styles.css";
export default function App() {
return (
<main>
<nav>
<ul>
<li>
<a href="/">Home</a>
</li>
<li>
<a href="/about">About</a>
</li>
<li>
<a href="/contact">Contact</a>
</li>
</ul>
</nav>
<Home />
<About />
<Contact />
</main>
);
}
// Home Page
const Home = () => (
<>
<h1>Home</h1>
<FakeText />
</>
);
// About Page
const About = () => (
<>
<h1>About</h1>
<FakeText />
</>
);
// Contact Page
const Contact = () => (
<>
<h1>Contact</h1>
<FakeText />
</>
);
const FakeText = () => (
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
);
Le composant BrowserRouter
reçoit toutes les pages de notre application. Il est généralement situé au point le plus haut de notre application. Ce composant se charge de lire l'adresse URL de la page, mais aussi de communiquer ces informations à d'autres composants.
import { BrowserRouter } from "react-router-dom"
export default function App() {
return (
<BrowserRouter>
<main>
// ...
</main>
</BrowserRouter>
);
// ...
}
Les trois pages restent visibles, car React ne sait pas encore quelle page est associée avec quelle adresse URL. C'est le rôle du composant Route
.
import { BrowserRouter } from "react-router-dom"
export default function App() {
return (
<BrowserRouter>
<main>
<nav>
// ...
</nav>
<Route path="/" component={Home} />
<Route path="/contact" componet={Contact} />
<Route path="/about" component={About} />
</main>
</BrowserRouter>
);
// ...
}
La ligne <Route path="/" component={Home} />
signifie que si l'URL contient /
, alors nous affichons le composant Home
.
Super ! Seulement le composant Home
s'affiche désormais !
Cependant, en cliquant sur le lien de Contact
, nous voyons deux composants s'afficher : Home
et Contact
. En effet, l'adresse URL de Contact
est /contact
, contenant /
.
Le Props exact
résout cette ambiguité en vérifiant que le to
correspond exactement à l'adresse URL : <Route exact={true} path="/" component={Home} />
.
Lorsque vous cliquez sur un lien, vous ressentez un temps de latence. Puisqu'on a utilisé la balise a
, un lien vous force à recharger toute l'application.
C'est particulièrement embêtant si vous avez stocké des informations dans un state -- par exemple un panier de courses : les states sont réinitialisés à leur valeur par défaut.
C'est pourquoi, le composant Link
simule un lien hypertexte a
en prévenant BrowserRouter
que la page actuelle a changé, ce qui, au passage, met à jour l'adresse URL.
export default function App() {
return (
<Router>
<main>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/contact">Contact</Link>
</li>
</ul>
</nav>
// ...
</main>
</Router>
)
}
Souvent, les adresses URL contiennent des paramètres, tels que l'identifiant d'un post de blog. Comment transmettre ces paramètres aux composants ? En précisant le format de ce paramètre dans le composant Route
.
Par exemple, en utilisant <Route path="/pages/:name" component={Post} />
, l'adresse URL /pages/mon-premier-post
transmet un props name="mon-premier-post"
au composant Post
.
Pour construire des chemins plus complexes, je vous renvoie à la documentation de path-to-regexp
.
export default function App() {
return (
<BrowserRouter>
<main>
<nav>
<ul>
<li>
<Link to="/pages/mon-premier-article">Mon premier article</Link>
</li>
<li>
<Link to="/pages/mon-second-article">Mon second article</Link>
</li>
</ul>
</nav>
</main>
// ...
<Route path="/post/:name" component={Post} />
</BrowserRouter>
);
}
// Post Page
const Post = (props) => {
console.log(props);
const {
match: {
params: { name }
}
} = props;
console.log(name);
return (
<>
<h1>{name.replaceAll("-", " ")}</h1>
<FakeText />
</>
);
};
A l'inverse, un lien vers un chemin paramétré peut être complexe à construire. La fonction generatePath
construit pour vous les chemins :
// (posts|comments) signifie que deux entités sont possibles : posts ou comments.
generatePath("/user/:id/:entity(posts|comments)", {
id: 1,
entity: "posts"
});
// users/1/posts
A l'issue de la page de connexion /login
, nous souhaitons que l'utilisateur soit redirigé sur son espace personnel situé à /my-account
.
Or, nous ne savons changer de page qu'à travers le composant Link
. On ne va tout-de-même pas demander à l'utilisateur de cliquer sur un bouton pour le rediriger !
La console de l'exemple précédent a affiché le contenu du props injecté par Route
dans Post
. Le props contient trois objets :
match
, que nous avons utilisé pour récupérer le paramètrename
extrait de l'adresse URL ;location
, qui contient l'adresse de la page actuelle -- laissons le de côté pour le moment ;history
, une structure qui contient l'historique des pages visitées.
Faire une redirection consiste juste à mettre à jour history
avec la page de redirection :
const Temp = ({ history }) => {
setInterval(() => history.push("/"), 3000);
return (
<>
<h1>Redirection</h1>
Dans 3 secondes, redirection sur la page d'accueil
</>
);
};
La sélection d'une page s'opère par la correspondance entre l'URL et une banque d'URL pré-définie. Comment gérer alors une adresse URL encore inconnue ? C'est nécessaire, si nous souhaitons personnaliser notre page d'erreur 404.
C'est là qu'intervient le composant Switch
; lequel reçoit une liste de composants Route
en entrée. Il cherche la correspondance entre la localisation actuelle et chacune des routes fournies ; il s'arrête à la première correspondance trouvée ou, en l'absence de correspondance, il prend la dernière route donnée.
// ...
<Switch>
<Route exact={true} path="/">
<Home />
</Route>
<Route path="/contact/">
<Contact />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/pages/:name" component={Post} />
<Route path="/tmp" component={Temp} />
<Route component={Lost} />
</Switch>
// ...
La librairie React Router
contient d'autres composants et props. Je vous conseille fortement de lire l'ensemble de la documentation, ce n'est pas bien long.