Il s'agit d'une version statique de l'intranet d'A. Jonquet, certaines fonctionnalités sont donc potentiellement non fonctionnelles.
Rejoindre la version dynamique 🔒
React
Navigation

Une application de partage de signets en React - partie 2

Ce TP est le deuxième d'une série où vous créez la base d'une application permettant d'afficher et de gérer une liste de signets.

Dans le premier TP, vous avez vu comment accéder à une une API à l'aide de l'API fetch.

Ce TP, se focalisera sur la simplification de l'affichage des composants à l'aide d'un routeur : Wouter.

Remarque importante

Les notes des TP seront obtenues à partir de vos dépôts Git, vous devrez donc prendre grand soin de la qualité de ces dépôts et de leurs « commits ».

De manière similaire, les descriptions de vos « commits » devront être claires et informatives, afin de permettre l'évaluation de la progression de votre travail.

Objectifs de la séance

  • Utilisation d'une API de données'
  • Utilisation d'un routeur
  • Gestion de données asynchrones

Ajout du routeur

Comme toujours dans l'environnement React, plusieurs solutions sont envisageables pour mettre en place un routeur dans une application react.

Un paquet largement utilisé par la communauté est React Router, cependant il s'agit d'une bibliothèque supportant de nombreuses fonctionnalités avec une documentation parfois incohérente.

Dans le cadre de ce TP, dans un souci de simplicité et afin de minimiser la dette technique, vous utiliserez une plus petite bibliothèque : Wouter. À l'heure de la rédaction de ce sujet, la version 2 de Wouter est la version officielle, mais la version 3 a été placé en « release candidate » sans date de sortie. Le sujet a été conçu avec la version 2 que vous pouvez installer à l'aide de la commande suivante :

npm install wouter@2

L'utilisation d'un routeur du coté front-end permet de simplifier la conception et l'organisation du flux applicatif en se concentrant sur l'agencement de vues et leurs relations.

Dans un premier temps, vous allez intégrer le routeur dans votre application. Vous commencerez par créer un sous-répertoire « src/routes » qui contiendra les descriptions des routes de l'application.

Dans ce répertoire, vous ajouterez un nouveau fichier src/routes/index.jsx, qui fournira un composant fournissant le routage de l'application. Il se contentera pour l'instant d'afficher le composant BookmarksList pour la route « / ». Dans un soucis de simplicité, vous allez utiliser Switch pour définir les routes, afin que les routes soient exclusives.

Vous pourrez ensuite utiliser ce routeur dans le composant App en remplacement du composant BookmarksList. Vous devriez maintenant disposer de la même application que précédemment, mais le routeur est maintenant opérationnel.

Travail à réaliser
  • Ajout du paquet Wouter.
  • Création du routeur de l'application.
  • Définition des routes dans App.

Gestion des erreurs

Vous ajouterez un nouveau composant NotFound dans le répertoire « src/views » affichant un message d'erreur de routage avec un lien vers l'accueil de l'application.

Le répertoire « src/views » à pour vocation de contenir des composants de vues de l'application. Idéalement, chaque écran de votre application devrait être représenté par un composant de vue.

Vous ajouterez une route par défaut affichant le composant Error.

Travail à réaliser
  • Création du composant NotFound.
  • Création de la route par défaut affichant une erreur.

La route du détail d'un signet

Pour l'instant l'application affiche une liste de signets. Cependant il est courant d'avoir besoin d'accèder à une vue détaillée d'un élément de la liste. Vous allez donc ajouter une nouvelle route permettant d'afficher le détail d'un signet, sous la forme « /bookmarks/:id » provoquant l'affichage de l'écran BookmarkDetail.

Le vue BookmarkDetail, étant rendu par le composant Route, celui-ci injecte une prop params contenant les paramètres de la route (id dans notre cas). Dans un premier temps, vous afficherez la valeur de paramètre pour controller le bon fonctionnement du routeur, par example avec le signet d'identifiant 2.

Pour obtenir le détail d'un signet, vous ajouterez une nouvelle fonction getBookmarkDetail au service bookmarks qui retournera une promesse du JSON décrivant le signet dont l'identifiant est passé en paramètre.

Dans la vue BookmarkDetail, vous utiliserez le hook useEffect pour invoquer la fonction getBookmarkDetail en fonction du paramètre id. Vous stockerez le résultat de la promesse dans une variable d'état. Si le résultat de la requête est une erreur, vous stockerez undefined dans la variable d'état.

En fonction de la valeur de la variable d'état, la vue BookmarkDetail affichera :

  • null un indicateur de chargement,
  • undefined une vue d'erreur de ressource non trouvée,
  • dans les autres cas, le nom du signet obtenu dans le JSON résultat de la requête.
Travail à réaliser
  • Définition de la route « /bookmarks/:id ».
  • Création de la vue BookmarkDetail.
  • Création du service d'obtention du détail d'un signet de l'API.
  • Affichage conditionnel en fonction de la réponse de la requête AJAX.

Affichage du détail d'un signet

Vous ajouterez un nouveau composant BookmarkDetail au répertoire « src/components », permettant l'affichage du détail d'un signet dont les données seront transmises sous forme de propriété React au composant.

Le composant devra afficher :

  • le nom du signet,
  • le lien vers l'url de destination du signet,
  • la description du signet,
  • la date de création du signet,
  • l'avatar du propriétaire du signet,
  • et la moyenne des notes du signet.

Vous utiliserez ce composant pour afficher le détail du signet obtenu par la requête AJAX dans la vue du détail d'un signet.

Dans votre application, pour permettre à vos utilisateurs d'atteindre le détail d'un signet, vous ajouterez un lien dans le composant BookmarkItem, utilisé dans la liste des signets, permettant de basculer vers la route « /bookmarks/:id » correspondant.

Vous pourrez supprimer le lien de support de l'url du signet et vous ajouterez un lien vers la vue du détail du signet. Conformément à la maquette suivante :

Illustration de l'affichage d'un bookmark
Travail à réaliser
  • Création du composant BookmarkDetail.
  • Affichage du détail d'un signet dans la vue BookmarkDetail.
  • Mise en place de liens vers le détail des signets dans la liste des signets.

Détail d'un utilisateur

De manière similaire au signet, vous allez ajouter une route permettant d'afficher le détail d'un utilisateur, sous la forme « /users/:id » provoquant l'affichage de la vue UserDetail.

Cette vue réalisera une requête AJAX pour obtenir les informations de l'utilisateur dont l'identifiant est passé en paramètre dans la route. La vue affichera un indicateur d'activité lors de la requête, la vue NotFound en cas d'erreur et les nom, prénom, login et avatar de l'utilisateur obtenue par la requête.

Pour réaliser la requête, vous ajouterez une nouvelle fonction getUserDetail au service bookmarks qui retournera une promesse du JSON décrivant l'utilisateur dont l'identifiant est passé en paramètre.

Pour finir, vous ferez en sorte que l'avatar des utilisateurs soit clickable et permette de basculer sur la vue détaillée de l'utilisateur associé.

Travail à réaliser
  • Définition de la route « /users/:id ».
  • Création de la vue UserDetail.
  • Création du composant UserDetail.

Réusinage du composant BookmarksList

Dans la vue du détail d'un utilisateur, nous souhaitons pouvoir afficher la liste des signets d'un utilisateur. Pour l'instant, le composant BookmarksList affiche la liste des de tous les signets, en réalisant lui-même la requête vers l'API, ce qui empêche la réutilisation du composant dans un autre cas, comme pour afficher les signets d'un utilisateur.

En effet, il s'agit d'une conception non optimale, le composant BookmarksList ne respecte pas le premier principe (« responsabilité unique ») de l'approche SOLID. Ce composant devrait se contenter d'afficher une liste de signets, sans réaliser de requête vers l'API, les signets à afficher lui seront transmis sous forme de propriété React (props).

Vous allez donc réusiner le composant BookmarksList pour qu'il puisse afficher une liste de signets transmis en paramètre sous forme de propriété React (props). La requête sera réalisée dans une nouvelle vue affichant un indicateur d'activité pendant la requête, puis la liste des signets une fois celle-ci résolue.

Vous devriez de nouveau avoir votre application fonctionnelle, mais avec une meilleure conception du composant BookmarksList.

Travail à réaliser
  • Réusinage du composant BookmarksList.
  • Création de la vue associée.

Ajout de la liste des signets d'un utilisateur

Vous devriez maintenant pouvoir ajouter la liste des signets d'un utilisateur dans le détail d'un utilisateur à l'aide du composant BookmarksList.

Le composant UserDetail réalisera une requête AJAX pour obtenir la liste des signets de l'utilisateur passé en paramètre dans la route, en utilisant une requête sur la collection de signets en ajoutant un filtre sur le propriétaire.

La vue affichera un indicateur d'activité lors de la requête et la liste des signets obtenue par la requête. La liste obtenue pas cette requête étant paginée, vous afficherez aussi une pagination si nécessaire. La gestion des données de la pagination sera réalisée en local dans le composant.

Travail à réaliser
  • Ajout de la liste des signets d'un utilisateur dans la vue UserDetail.

Conservation de la page courante au cours de la navigation

Vous devriez constater dans votre application que si vous changer de page sur la liste des signets, que vous basculer la vue sur le détail d'un signet ou d'un utilisateur, puis que vous revenez à la liste des signets, celle-ci à perdue la page courante et affichae la première page des signets par défaut.

Ce comportement s'explique par le fait que la page courante est stoquée dans la vue affichant la liste des signets, et que cette vue est détruite lors de la navigation vers une autre vue. Lorsque la navigation revient sur la liste des signets, une nouvelle vue est créée, et la page courante est de nouveau réinitialisée avec sa valeur par défaut.

Il s'agit là d'une expérience utilisateur assès décevante, vous allez donc résoudre ce problème.

La solution la plus simple, consiste à remonter l'information au niveau d'un composant parent qui pérsistera au cours de la navigation. Dans notre cas, il s'agira du composant App, qui est le composant racine de l'application.

Vous déplacerez donc la variable d'état page du composant BookmarksList vers le composant App. Vous ferez ensuite en sorte que cette variable d'état soit transmise au composant BookmarksList sous forme de props.

Travail à réaliser
  • Déplacement de la variable d'état page du composant BookmarksList au composant App.
A. Jonquet DUT-INFO/REIMS