6 Routes à connaître si tu utilises Remix (guide complet)
Tags: remix, react, webdev, remixjs
Published: 2024-02-13 07:21:35

Envisages-tu de tester ou même d'utiliser le framework [Remix](https://remix.run) pour ton prochain projet ?

Pour cela, il va falloir te familiariser avec son puissant *routing*. Cet article te liste les [**6** types de routes](https://www.youtube.com/watch?v=TOMMXhgUQfI) que tu vas utiliser au quotidien avec Remix. Si tu préfères lire la doc, Remix [explique tout en détail](https://remix.run/docs/en/main/file-conventions/routes) sur le site.


## Le routing, c'est quoi ? 

Commençons par définir ce qu'est le **routing**

> C'est le chemin (sous forme d'URL) qui permet d'accéder à ton site internet

Exemples :
- [leboncoin.fr](https://leboncoin.fr) te permet d'accéder à la page d'accueil du bon coin, sa route "index".
- [leboncoin.fr/annonces/offres](https://leboncoin.fr/annonces/offres) te permet d'accéder à une deuxième page du bon coin. La page est différente de la première, le chemin d'accès dans l'URL est différent. C'est une deuxième route.

Tous les sites possèdent minimum une route (qu'on va appeler route *index*, ou route *par défaut*).

Ce concept n'est pas récent. À mes débuts dans le développement, j'intégrais mes premières pages en HTML et PHP. La convention était de nommer nos fichiers **index.html** et **index.php**. Ces fichiers étaient ensuite accessibles au nom de domaine local. Par exemple, `localhost:8000`. Sans le savoir, j'avais déjà créé ma première *route* index.

Avec l'arrivée de **React** et de ses framework, le routing se fait généralement sans configuration de notre part. (sauf si tu utilises React-Router, mais si c'est le cas, tu es au bon endroit !)

## Explication vidéo

Nous avons fait un guide vidéo pour t'expliquer le routing de Remix avec plus d'exemples. 

{% youtube TOMMXhgUQfI %}

## Créer sa première route (type 1)

Lorsques tu génères un nouveau projet Remix avec l'un de ses nombreux template, une route par défaut aura déjà été créée. Elle se situe dans ton dossier `app/routes` et se nomme **__index.tsx**.

```tsx
export default function Index() {
	return (
		<h1>Hello world !</h1>
	);
}
```

Voici les **2 règles** à respecter pour créer une route avec la configuration par défaut de Remix :
- Créer un fichier au format **.jsx** ou **.tsx** dans le dossier `app/routes`.
- Le nommer (son nom va définir le chemin pour y accéder dans l'URL.

Dans l'exemple ci-dessous, nous avons ajouté un composant React à l'intérieur de notre fichier. Cette vue sera accessible à la page d'accueil de notre site (par défaut `localhost:3000`)

> Mais il n'est pas obligatoire d'exporter des composants React depuis nos routes.

Cela dépend de ton besoin. Si tu veux juste créer un endpoint API (une route qui renvoie du JSON, par exemple), tu n'as pas besoin de déclarer un composant React.

```tsx
export const loader = () => {
   return { name: 'Virgile' }
}
```

Voici un exemple d'une route Remix, accessible à l'URL `localhost:3000/api`. Elle renvoie un objet au format JSON.

```json
{ name: "Virgile" }
```

## Création d'une route dynamique (type 2)

Pour créer une route dynamique, nous devons utiliser un nommage de fichier précis. Il nous suffit d'ajouter le préfixe **$** à notre nom de fichier.

Par exemple, si je souhaite afficher le détail de l'utilisateur *Virgile** à l'adresse `http://localhost:3000/users/virgile`, je vais implémenter cette logique en deux étapes :

- Nommer un fichier dans le dossier `app/routes`, nommé `users.$username.tsx`
- Exporter par défaut un composant React pour afficher une vue, avec les informations de cet utilisateur

Regardons avec un exemple.

```tsx
import { useParams } from '@remix-run/react';
export default function Username() {
    const username = useParams().username;
	return (
		<h1>Salut {username} !</h1>
	);
}
```
Ici, nous donnons une instruction à Remix. Nous lui demandons de créer une route au chemin `users/virgile`. Le point (`.`) dans le nommage du fichier nous permet d'ajouter un *slash* dans l'URL. Ensuite, le *$* nous permet de nommer la clé du paramètre dans l'URL.

Nous récupérons ensuite ce paramètre dynamique, nommé *username* dans notre composant React, côté client à l'aide du hook **useParams()** que nous importons depuis Remix.

Ce fichier nous permet donc de créer une route qui va afficher une vue côté client, avec une valeur dynamique en fonction de la valeur que nous entrons dans l'URL.

![salut virgile](https://algomax-public.s3.eu-west-3.amazonaws.com/image_f689049259.png)

La valeur de notre variable **username** est déterminée par le paramètre d'URL (soit *virgile*, dans cet exemple)

## Création d'une route imbriquée (type 3)

La route *imbriquée* est similaire à la route dynamique. Nous nommons le fichier de la même manière qu'une route dynamique. La seule différence, c'est le contenu de la route **parent** (dans notre exemple, la route **users.tsx**) est visible sur la page. C'est très pratique pour afficher par exemple système d'onglets dans notre application. 

![Exemple de page avec des onglets](https://algomax-public.s3.eu-west-3.amazonaws.com/tabs_502db141b3.jpeg)

Nous pourrions très bien reproduire cet exemple sous forme de route imbriquée. La route parent afficherait les onglets, et le contenu de l'onglet (Subtopic 1) serait affiché dans la route enfant.


Faisons d'abord une petite refactorisation.

```tsx
import { Link } from '@remix-run/react';

export default function Users() {
	return (
		<div>
			<h1>Liste des utilisateurs</h1>
			<ul>
				{['Virgile', 'Cédric'].map((username) => (
					<Link to={`/users/${username}`} key={username}>
						{username}
					</Link>
				))}
			</ul>
		</div>
	);
}
```
Nous affichons maintenant une liste de deux utilisateurs sur la route `localhost:3000/users`, *Virgile* et *Cédric*.
Nous avons également des liens pour accéder à leur information.

Spoiler, mais ça ne va pas avoir l'effet désiré. On n'est cependant pas loin du but.
En théorie, il suffirait de changer l'URL à `localhost:3000/cedric` pour afficher la vue pour cet utilisateur (c'est la route dynamique que nous avons créée plus haut).

Malheureusement, après avoir cliqué sur le lien, on se rend compte que la page n'a pas changé 🤔 ??
![image.png](https://algomax-public.s3.eu-west-3.amazonaws.com/image_ec2c10077b.png)

Et bien, si. Nous avons réussi à donne l'instruction à Remix de créer une route **imbriquée**. Sauf qu'on a oublié un composant magique nous permettant de placer la position de l'enfant dans le DOM.

En fait, la page ci-dessus affiche toujours le contenu du parent (les liens de nos utilisateurs), mais elle n'affiche pas la route enfant car on ne lui a pas donné l'instruction. (il n'y a donc aucun bug, rassurez-vous)

> Que dois-je faire pour faire apparaître ma route enfant ?

Le composant `<Outlet/>` est la pièce manquante pour bénéficier des routes imbriquées avec Remix. En effet, si nous accédons à la route parent (`localhost:3000/users`), Remix affiche la route `users.tsx`. Mais si on accède à la route `localhost:3000/users/cedric`, Remix va regarder le nom de notre fichier `users.$userId.tsx`. 

Et il va vérifier trois éléments :
- Est-ce qu'il y a un paramètre d'URL dynamique (symbolisé par le `$`)
- Est-ce qu'il existe une route parent (dans notre cas, `users.tsx`
- Est-ce que la route parent possède un composant `<Outlet/>`

Rajoutons maintenant le [composant Outlet](https://remix.run/docs/en/main/components/outlet) et regardons ce qui se passe.

```tsx
import { Link, Outlet } from '@remix-run/react';

export default function Users() {
	return (
		<div>
			<h1>Liste des utilisateurs</h1>
			<ul>
				{['Virgile', 'Cédric'].map((username) => (
					<Link to={`/users/${username}`} key={username}>
						{username}
					</Link>
				))}
			</ul>
			<Outlet />
		</div>
	);
}
```

![La route imbriquée s'affiche correctement](https://algomax-public.s3.eu-west-3.amazonaws.com/image_aff718efe0.png)

En résumé, ajouter une route imbriquée est relativement *simple*. Il suffit de rajouter le composant `<Outlet/>` dans la route parent. Et Remix se charge du reste.

## Création d'une route layout (type 4)

Reprenons l'exemple de nos onglets pour mieux comprendre l'intérêt d'une route **layout**. 
On va commencer par la définir, en la comparant à une route imbriquée.

> Une route layout, c'est une route imbriquée, mais le chemin n'est pas visible dans l'URL.

Par exemple, si vous souhaitez afficher un composant spécial sur certaines pages, mais pas sur d'autres (ou bien un modal qui apparaît après 5 secondes, c'est vous qui voyez), c'est totalement possible grâce aux routes *Layout*.

Pour créer une route layout, il suffit de rajouter le préfixe `_` (underscore) à la route parent. Son nom va disparaître de l'URL.
Essayons tout de suite avec notre route `users.tsx`.

(Le contenu du fichier ne change pas, seulement son nom)

```
import { Link, Outlet } from '@remix-run/react';

export default function Users() {
	return (
		<div>
			<h1>Liste des utilisateurs</h1>
			<ul>
				{['Virgile', 'Cédric'].map((username) => (
					<Link to={`/${username}`} key={username}>
						{username}
					</Link>
				))}
			</ul>
			<Outlet />
		</div>
	);
}
```

Il faut aussi modifier le fichier `users.$username.tsx` pour qu'il soit considéré comme "faisant partie du layout".

```
import { useParams } from '@remix-run/react';

export default function Username() {
	const username = useParams().username;
	return <h1>Salut {username} !</h1>;
}
```

Maintenant, notre liste d'utilisateurs ne sera plus visible au chemin `localhost:3000/users`. Elle ne sera plus visible du coup, pas même à l'URL `localhost:3000` (c'est la route _index.tsx qui s'affiche à la place).

Le détail de notre utilisateur sera cependant accessible à la route enfant `localhost:3000/cedric`, ainsi que le contneu de notre layout (la liste de nos deux utilisateurs)

## Créer une route ressource (JSON, PDF, CSV ...) (type 5)

Vous vous souvenez de la route basique qu'on a créé en tout début de l'article ? Une [route ressource](https://remix.run/docs/en/main/guides/resource-routes#creating-resource-routes) est exactement pareil. 

Il suffit de créer un fichier dans le dossier `app/routes`, mais au lieu d'exporter un composant React par défaut (notre vue), nous exportons une méthode nommée `loader` (pas besoin de l'exporter par défaut)

Essayons avec un exemple. Je souhaite afficher une image aléatoire à l'URL `localhost:3000/image`. Je vais donc récupérer mon image depuis le site [picsum.photos](https://picsum.photos)

Il me suffit donc de créer un fichier nommé `image.tsx` (dans le dossier `app/routes`), puis d'exporter une *fonction* nommée `loader`
Essayons voir.

```
export const loader = async () => {
	const response = await fetch('https://picsum.photos/200/300');
	const blob = await response.blob();
	return new Response(blob, {
		headers: {
			'Content-Type': 'image/jpeg',
		},
	});
};
```

![resource-route.gif](https://algomax-public.s3.eu-west-3.amazonaws.com/resource_route_203bd1f2a2.gif)

Je n'ai jamais créé une route API aussi facilement. 

## Créer une route 404 (type 6)

Nous allons maintenant créer notre dernier type de route, la fameuse page *Erreur 404*. 
Si vous lisez l'article depuis le début, vous comprendrez vite comment l'implémenter.
Indice : C'est comme une route dynamique, mais le paramètre d'URL n'est pas nommé.

> Il faut nommer le fichier `$.tsx`

Pour afficher une vue à n'importe quelle page que Remix n'identifie pas comme étant un chemin valide, il faut également exporter un composant React par défaut. Passons à l'implémentation.

```app/routes/$.tsx
import { useLocation } from '@remix-run/react';

export default function FourOhFour() {
	const location = useLocation();
	return (
		<h1 style={{ fontSize: 18 }}>
			Oops, on a pas trouvé la route{' '}
			<span style={{ color: 'GrayText' }}>{location.pathname}</span> !
		</h1>
	);
}
```
Essayons un chemin pour voir. Au hasard, `localhost:3000/youtube/abonnez-vous`.

![Route 404](https://algomax-public.s3.eu-west-3.amazonaws.com/404_route_951a872cfc.gif)

Petites précisions :
- Remix priorise les routes nommées. Si vous tapez `localhost:3000/image` dans l'URL, Remix va d'abord regarder les routes nommées, pas dynamiques (un match exact) avec le nom. C'est le cas pour nous avec le fichier `image.tsx`
- Ensuite s'il ne trouve pas, il va chercher une route dynamique (avec le préfixe `$`). C'est le cas avec le fichier `_users.$username.tsx`, qui va matcher n'importe qu'elle URL à la place de l'étoile `localhost:3000/*`, à l'exception des routes nommées (exact match), et des routes imbriquées (plusieurs `/` (slash) dans l'URL)
- Nous essayons d'accéder à la route `localhost:3000/youtube/abonnez-vous`, qui n'est donc pas un paramètre d'URL car il y a un `/`. On renvoie donc sur une page 404.

## Conclusion

Nous venons de voir tous les types de page nécessaires pour vous permettre de créer des belles [applications web sur mesure](/creation-applications-web-sur-mesure). Si vous voulez aller plus loin et configurer vous-même vos règles de routing (ou changer les préfixes, tels que `.`, `$` et `_`, c'est possible. La librairie [remix-flat-routes](https://github.com/kiliman/remix-flat-routes) vous le permet, et je l'utilise dans tous mes projets !