codelynx.dev
🇫🇷🇬🇧

Retour 16/11/2024

Ce dont personne ne parle à propos de Zustand

Écris par Melvyn Malherbe le 16/11/2024


Zustand est depuis quelques années une librairie qui fait pour moi "partie de React."

C'est-à-dire que...

La méthode qu'il expose (create) est devenu essentiel dans presque toutes mes applications.

La magie de Zustand c'est qu'il vient résoudre un gros problème, la gestion de state globaux, de manière si simple et efficace que c'est déstabilisant.

On va parler de Zustand et pourquoi tu as besoin de cette outil.

C'est quoi Zustand ?

C'est une librairie pour gérer des stores dans React !

Un Store permet de stocker des données et des actions qui seront accessibles partout dans ton application.

Par exemple tu pourrais vouloir stocker un panier :

JS
const useCart = create((set, get) => ({
  // Notre état
  items: [],
  // Une méthode stable qui vient ajouter un item
  addItem: (item) => set({ items: [...get().items, item] }),
  // Une méthode stable qui vient supprimer un item
  removeItem: (item) => set({ items: get().items.filter((i) => i !== item) }),
}));

Contrairement à un context, ce store sera accessible n'importe où dans ton application :

JS
import { useCart } from "./useCart";

export default function App() {
  const { items, addItem, removeItem } = useCart();

  return (
    <div>
      <button onClick={() => addItem("item1")}>Add item</button>
      <button onClick={() => removeItem("item1")}>Remove item</button>
      <ul>
        {items.map((item) => (
          <li key={item}>{item}</li>
        ))}
      </ul>
    </div>
  );
}

En règle générale, si tu veux un state global ce que tu veux c'est Zustand et jamais useContext.

Pourquoi Zustand ?

Il apporte pas mal d'optimisations notamment le fait de pouvoir "sélectionner" des données :

JS
const addItem = useCart((state) => state.addItem);

Quand tu fais ce code, tu viens t'abonner à l'évènement addItem et ton component ne se re-render que lorsque addItem change (c'est-à-dire jamais car c'est une méthode).

Il possède des hooks d'optimisation comme useShallow etc... qui permettent d'éviter des re-renders etc...

En règle générale useContext n'est pas le bon outil pour gérer des states globaux.

Quelle est la feature dont personne ne parle ?

La magie de Zustand c'est de pouvoir interagir avec React en dehors de React.

C'est-à-dire que tu peux modifier un store en dehors d'un component.

Un des components que j'aime beaucoup sur Codeline c'est un component qui affiche des AlertDialog :

JS
const useAlertDialog = create((set, get) => ({
  dialogs: [],
  addDialog: (dialog) => set({ dialogs: [...get().dialogs, dialog] }),
  removeDialog: (dialog) =>
    set({ dialogs: get().dialogs.filter((d) => d !== dialog) }),
}));

const AlertDialogs = () => {
  const dialogs = useAlertDialog((state) => state.dialogs);

  const dialogToShow = dialogs[0];

  if (!dialogToShow) return null;

  return <AlertDialog {...dialogToShow} />;
};

En gros ce component me permet d'afficher des Alert dans mon application React sans avoir besoin de venir "l'afficher" partout.

Par exemple :

  • Quand l'utilisateur va faire une action destructive, j'affiche une alert qui lui demande de confirmer

Le truc c'est que pour l'utiliser avec un React tu dois faire ça :

JS
const Demo = () => {
  // Ajouter une première ligne pour pouvoir utiliser useAlertDialog
  const addDialog = useAlertDialog((state) => state.addDialog);

  const handleClick = () => {
    // Appeler notre méthode de store
    addDialog({
      title: "Demo",
      description: "Demo",
      action: {
        label: "Confirm",
        onClick: () => {
          console.log("Confirm");
        },
      },
    });
  };

  return <button onClick={handleClick}>Click me</button>;
};

L'avantage de Zustand c'est justement de pouvoir utiliser notre Store dans des simples méthodes.

Ce que j'ai fait c'est ça :

JS
export const alertDialog = {
  add: (params: ConfirmationDialogProps) => {
    useModalStore.getState().enqueueConfirmationModal(params);
  },
  // autre méthode...
};

De cette manière je peux utiliser alertDialog dans mon application React sans avoir besoin d'importer le hook etc...

JS
const Demo = () => {
  const handleClick = () => {
    // Je peux directement utiliser alertDialog
    alertDialog.add({
      title: "Demo",
      description: "Demo",
      action: {
        label: "Confirm",
        onClick: () => {
          console.log("Confirm");
        },
      },
    });
  };

  return <button onClick={handleClick}>Click me</button>;
};

Quand je fais ça, je viens "en dehors de React" sans utiliser de hook interagir avec mon store et afficher une Dialog.

C'est ça la feature assez géniale de Zustand.

Voici à quoi ça ressemble :

Mais attends, tu es sûr que c'est bien ?

Attention, il faut savoir que les hooks sont là pour une raison.

Il ne faudrait en général pas récupérer une donnée sans un hook car ton component ne sera pas "abonné" au changement de celle-ci.

Mais pour des événements, c'est totalement ok car Zustand fonctionne d'une manière où toutes les méthodes ne sont jamais recréées.

Dans ma formation React il y a un module complet sur Zustand car je pense sincèrement qu'il est essentiel de comprendre cette librairie.

Le meilleur moyen d'apprendre React !

Rejoins par développeurs, cette formation reçoit une note de 4.7 / 5 🚀

Reçois 12 leçons premium pour maîtriser React et faire partie des meilleurs

Dans le même style il est intéressant pour toi de comprendre la différence entre NextJS et React ou la différence entre React et VueJS ou même tout simplement savoir ce qu'es vertiablement React.

BeginReact

Cours React gratuit

Accède à des exercices, des vidéos et bien plus sur React dans la formation "BeginReact" 👇