• 15 heures
  • Difficile

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 01/12/2023

Adaptez votre utilisation de Redux aux évolutions du code

Dans cet ultime chapitre, nous allons nous éloigner un peu de Redux pour découvrir d’autres outils de state management.

Utilisez le hook useReducer de React

Comme précisé dans la première partie, Redux existe depuis assez longtemps dans l'écosystème React. Ce n’est donc pas étonnant qu’il ait influencé React, notamment lors de l'introduction du système de hooks.

En effet, les hooks sont plutôt récents puisqu’ils ont été ajoutés à React en 2019, et l’un des hooks primitif est directement inspiré de Redux : useReducer  .

useReducer  est comparable à useState  mais, en plus d’un state initial, on passe un reducer  . De plus, au lieu d’une fonction setState  , on récupère une fonction dispatch  .

Voici, par exemple, le hook useFetch  avec un useReducer  au lieu des useState  :

import { useReducer } from 'react'
 
function fetchReducer(state, action) {
    if (action.type === 'fetching') {
        return { ...state, isLoading: true }
    }
    if (action.type === 'resolved') {
        return { isLoading: false, data: action.payload, error: null }
    }
    if (action.type === 'rejected') {
        return { isLoading: false, data: null, error: action.payload }
    }
    throw new Error('Invalid actions')
}
 
export function useFetch(url) {
    const [state, dispatch] = useReducer(fetchReducer, {
        isLoading: true,
        data: null,
        error: null,
    })
 
    const { isLoading, data, error } = state
 
    useEffect(() => {
        if (!url) return
        dispatch({ type: 'fetching' })
        async function fetchData() {
            try {
                const response = await fetch(url)
                const data = await response.json()
                dispatch({ type: 'resolved', payload: data })
            } catch (err) {
                console.log(err)
                dispatch({ type: 'rejected', payload: err })
            }
        }
        fetchData()
    }, [url])
    return { isLoading, data, error }
}

L'avantage de useReducer  , c’est qu'il permet de contrôler à un seul endroit (dans le reducer) quels changements de state sont autorisés. Il est également très facile de tester un reducer, comme on l’a vu dans le chapitre précédent.

En revanche, useReducer  ne remplace pas du tout Redux puisque le state reste lié au composant où il est déclaré (contrairement à Redux qui expose un state en dehors de React).

Mon conseil, c’est d’utiliser useReducer  lorsqu’un ou plusieurs useState  deviennent trop compliqués !

Comprenez les limites de Redux

Redux est un outil très pratique qui va vous permettre de développer de meilleures applications ! Cependant, Redux a aussi quelques défauts que nous allons voir dans cette section.

Dans les projets à grande échelle qui utilisent Redux, on a parfois des problèmes de mutation directe du state (au lieu du destructuring/Immer) et/ou des rendus inutiles à cause de selectors qui créent de nouvelles références. Ces problèmes ne sont pas vraiment liés à Redux directement. Cependant, des erreurs peuvent vite arriver, et il n’est pas toujours évident de détecter ces problèmes.

La manipulation des actions asynchrones est assez rudimentaire avec Redux. Pour des choses simples comme des timers ou des requêtes à un serveur, c'est souvent suffisant ; mais pour manipuler de nombreux processus asynchrones qui interagissent entre eux, on a souvent besoin de faire appel à un outil supplémentaire. L’outil le plus populaire dans ce domaine est probablement Redux-Saga, que vous pouvez trouver ici.

Un autre inconvénient de Redux est la quantité de code nécessaire pour faire fonctionner notre logique. Redux Toolkit et Immer nous ont permis de mitiger ce problème, mais l’implémentation de certaines fonctionnalités reste très répétitive. C’est notamment le cas pour la récupération de données depuis le serveur. Dans Shiny, par exemple, les fonctionnalités freelances  et survey  sont quasiment identiques !

Pour résoudre cela, je vous propose de découvrir un outil qui n’est pas lié à Redux, mais que l’on peut faire cohabiter avec Redux pour gérer les données qui proviennent du serveur : React-Query.

Découvrez et installez React-Query

React-Query est un outil de state management plus spécifiquement conçu pour gérer les données qui proviennent d’un serveur. Comme son nom le laisse deviner, React-Query est un outil qui fonctionne uniquement avec React.

Tout comme Redux, React-Query utilise un système de state global en dehors de React. En revanche, la manière d'interagir avec ce state est différente. Avec React-Query, on va utiliser un hook useQuery  pour modifier mais aussi lire le state global.

Avant d’utiliser le hook useQuery  , il va falloir installer et initialiser React-Query :

yarn add react-query

Tout comme React-Redux, React-Query nécessite un Provider (  QueryClientProvider  ) pour fonctionner. Ce dernier attend une props client  qui va correspondre au queryClient  de notre application. Le queryClient  est un objet qui va contenir les différentes données, un peu comme le store de Redux. Il va donc falloir modifier le fichier arc/index.jsx  :

// on importe QueryClient et le Provider
import { QueryClient, QueryClientProvider } from 'react-query'
 
// on créer le queryClient
const queryClient = new QueryClient()
 
ReactDOM.render(
    /* On englobe toute l'application dans le Provider */
    <QueryClientProvider client={queryClient} >
        <Provider store={store}>
            {/* ... */}
        </Provider>
    </QueryClientProvider>,
    document.getElementById('root')
)

On est maintenant prêt à utiliser le hook useQuery  dans nos composants !

Migrez votre code vers React-Query

Le hook useQuery  attend trois paramètres :

  • queryKey  : une chaîne de caractères ou un tableau qui identifie la ressource serveur.

  • queryFn  : la fonction qui fait l’appel au serveur et doit retourner une promesse.

  • options  : un objet optionnel pour passer des paramètres supplémentaires.

Voici à quoi ressemble le useQuery  pour la liste des freelances :

 useQuery('freelances', async () => {
    const response = await fetch('http://localhost:8000/freelances')
    const data = await response.json()
    return data;
 });

À quoi sert le paramètre queryKey  ?

React-Query utilise un state global pour stocker les résultats des requêtes. Il utilise donc le paramètre queryKey  pour identifier la requête. Ainsi, si on utilise useQuery  avec la même queryKey  dans une autre partie de l’application, React-Query utilisera les données au lieu de relancer la requête !

Maintenant que l’on a correctement appelé useQuery  , on va pouvoir récupérer les données via le retour du hook. En effet,useQuery retourne un objet qui contient de nombreuses informations sur l’état de la requête. On va donc déstructurer cet objet et utiliser les différentes valeurs dans le rendu :

 const {
    // les données renvoyées par le serveur
    // null si la requête n'est pas encore résolue
    data,
    // booléen qui indique si la requête est en cours
    isLoading,
    // l'erreur renvoyé par le serveur
    // ou null si pas d'erreur
    error,
 } = useQuery(/* ... */);

L’avantage de React-Query, en plus d'être bien plus concis, c’est qu’il inclut tout un ensemble de comportements par défaut qui améliorent l’expérience utilisateur. Par exemple, React-Query rafraîchit automatiquement les données lorsque l’utilisateur revient sur la page après l’avoir quittée. Il est bien évidemment possible de configurer ces comportements, mais je vous laisse découvrir cela par vous-même!

Vous pouvez retrouver le code de cette vidéo sur la branche P4C5S4-react-query du repository à cette adresse.

Exercez-vous

Pour ce dernier exercice, vous devez mettre en place React-Query dans Shiny, et donc supprimer les fonctionnalités Redux qui ne sont plus utilisées.

Je vous préviens : vous allez ajouter un peu de code et en supprimer bien plus !

Une fois que vous avez terminé, allez jeter un œil à la version corrigée sur la branche P4C5S5-solution du repository React-Redux-Shiny à cette adresse.

En résumé

  • Le hook useReducer  de React est un mélange entre useState  et un reducer Redux.

  • React-Query est un outil de state management qui permet de gérer la récupération de données d’une API dans React.

  • Pour utiliser React-Query, il faut englober l’application dans le QueryClientProvider  .

  • Le hook useQuery  de React-Query peut ensuite être utilisé pour récupérer des données d’une API.

Exemple de certificat de réussite
Exemple de certificat de réussite