Gérer la résilience d’une application par composant avec React

Jérôme Boukorras
4 min readDec 2, 2019

Aujourd’hui, une application web doit proposer la meilleure expérience possible aux utilisat·eur·rice·s. Cette expérience est définie par énormément de critères. Certains sont connus et assez évidents comme l’ergonomie ou la performance. D’autres sont malheureusement un peu moins appliqués comme l’accessibilité ou encore la résilience, sujet de cet article.

Mais d’abord qu’est-ce que nous appelons ici “résilience” ? La résilience c’est la faculté qu’aura une application ou, plus localement, un composant d’une application à fonctionner malgré des conditions défavorables. Ici, je ne resterai qu’au niveau composant. Je n’aborderai pas (dans cet article en tout cas) les modes hors ligne et autres possibilités offertes par les progressives web app.

Lorsque nous concevons une interface graphique, nous partons toujours du principe que tout fonctionne bien. Dans la réalité, c’est bien souvent différent : une connexion Internet de mauvaise qualité ou un serveur qui plante arrivent bien plus souvent qu’on ne veuille l’admettre. C’est pourquoi, une bonne pratique est de tout prévoir, ou presque. Il y a, bien sûr, des cas dans lesquels le bon fonctionnement du composant voire de l’application est impossible. Si ces cas se présentent, il est impératif d’en informer la personne utilisant votre application avec un message clair, et le cas échéant, une action associée. Prenons un cas assez courant : un composant doit aller chercher du contenu via une API et l’afficher dans une liste. Plusieurs cas peuvent se présenter :

  • Le composant est en train de faire sa requête.
  • La requête s’est bien passée, les données sont affichées.
  • La requête s’est mal passée, le serveur répond avec une erreur.
  • La requête s’est bien passée, mais la réponse est vide.
  • L’accès aux données n’est pas autorisé à cet utilisat·eur·rice.

Ce ne sont là que les cas les plus courants, mais cette liste est loin d’être exhaustive et pourrait être complétée avec des cas bien plus spécifiques à chaque projet.

L’affichage dans un composant

React est plutôt complet, mais il ne permet pas encore de gérer cette résilience par composant. Le composant <Suspense/> permettra à l’avenir de gérer l’affichage de l’état de chargement. Mais comment gérer ces autres cas ?

Partons du principe que notre composant ait une propriété “status” (nous verrons plus tard comment la créer). Cette propriété est une chaîne de caractères pouvant être soit “LOADING”, “OK”, “ERROR”, “EMPTY” ou “DENIED”. Nous pouvons gérer l’affichage de notre composant de la manière suivante :

Le composant affiche la valeur d’un objet correspondant à la clé correspondant à notre “status”. Cette valeur étant du code JSX, nous avons donc du code JSX conditionné à la valeur de notre propriété “status”. Cette méthode permet de gérer de nombreux cas dans lesquels l’affichage d’un composant ou bien d’un autre est conditionné à une variable.

Afin d’être réutilisés un peu partout dans l’application, les différents états possibles sont stockés dans un objet situé dans un fichier à part.

Notre composant récupère aussi la propriété “data” qui contiendra les éléments à afficher dans une liste.

La gestion du statut dans le container

Afin de d’enrichir notre composant avec la propriété “status”, “data” et “onRetryClick”, nous allons utiliser plusieurs hooks : “useState”, “useCallback” et “useEffect”. La propriété sera créée avec le “useState”.

Le hook “useEffect” sera utilisé pour appeler la fonction “fetchData” au chargement de notre composant. À l’aide du hook “useCallback”, nous créons également une fonction qui sera appelée au clic sur le bouton “réessayer”, visible en cas d’erreur du serveur. Il servira à re-tenter un appel vers le serveur.

Requête vers le serveur

Afin d’obtenir les données, nous faisons une requête GET vers l’url “/test”. Pour les besoins de cet article, le serveur est un petit script NodeJs / Express dont la requête vers cette url répondra aléatoirement un code d’erreur différent avec une latence simulée de une seconde. Cela permettra de tester tous les cas de figures supportés.

Cette requête est effectuée par la fonction “fetchData” qui prend en paramètres “setStatus” et “setData”, afin de respectivement mettre à jour le statut de la requête et les données récupérées. Cette fonction va ensuite trouver la correspondance entre le code retourné par la requête et le statut approprié, puis mettre à jour l’état de notre composant.

Dans cet exemple, j’associe des messages d’erreur à des codes d’erreur envoyés par le serveur. Il ne faut pas en abuser. En effet, trop d’informations données aux utilisat·eur·rice·s sur ce point peut créer des failles de sécurité.

J’utilise ce pattern depuis peu et il correspond pour l’instant à mes besoins. Cependant, la liste des cas que j’ai cité est loin d’être exhaustive et il y a potentiellement beaucoup de cas génériques ou spécifiques à couvrir. N’hésitez pas à tester cette méthode et à l’améliorer, le code source utilisé dans cet article est disponible sur Github.

--

--