Fermer

mai 3, 2024

Explorer les solutions de gestion d’état au-delà de Redux et MobX

Explorer les solutions de gestion d’état au-delà de Redux et MobX


La gestion d’état est un aspect crucial du travail avec React, et le choix d’un outil de gestion d’état approprié est primordial. Dans cet article, nous présenterons les solutions de gestion au-delà de Redux et MobX.

Un état dans un composant React est constitué de données encapsulées, c’est-à-dire de données privées qui modifient le comportement d’un composant à un moment donné de l’exécution de l’application. Dans React, deux concepts de modèle de conception sont utilisés pour propager les modifications dans votre application : le modèle d’observateur et le modèle d’état. Ces modèles font partie des 23 modèles de conception populaires Gang of Four du livre. Modèles de conception : éléments de logiciels orientés objet réutilisables.

Le modèle de conception d’état est un type de modèle comportemental qui permet à un objet de modifier son comportement lorsque son état interne change. Parallèlement, le modèle de conception de l’observateur est un type de modèle comportemental dans lequel un objet, appelé observateur, écoute les changements survenus dans un autre objet, appelé observable. L’observateur est averti lorsque des changements se produisent dans l’observable, ce qui correspond essentiellement au comportement des composants React DOM et React.

Pour la gestion d’états complexes, des outils React tels que useReducer, Redux, MobX, etc. sont utilisés, et ils adhèrent tous à l’architecture Flux, comme indiqué ci-dessous.

Action - répartiteur - magasin - vue

L’image représente le flux unidirectionnel de données dans une architecture Flux typique.

Conditions préalables

  • La connaissance de React et React Hooks est requise.
  • La connaissance de la syntaxe JavaScript et ES6 est requise.
  • Comprendre comment installer les dépendances à l’aide de npm est nécessaire.
  • Des connaissances de base en gestion d’État ne sont pas requises.

Configuration du projet

Nous créerons un projet ReactJS dans lequel nous présenterons des exemples de gestion d’état, notamment MobX, Redux, Zustand, Recoil et Jotai.

Pour échafauder un projet React, veuillez ouvrir votre terminal et taper les commandes suivantes :

npm create vite
// Follow the commands to scaffold for a react, javascript
cd [project name]
npm install
npm run dev

Copiez l’adresse affichée sur votre terminal et accédez à votre navigateur, puis collez l’URL. Vous devriez voir une page par défaut comme celle-ci.

Gestion de l’état dans React

En explorant la gestion d’état, nous créerons plusieurs variantes de l’application de compteur populaire.

Crochets

Le hook useState permet l’ajout d’une gestion d’état aux composants fonctionnels dans React. Le hook useState facilite la gestion de l’état dans les composants fonctionnels sans avoir besoin de composants de classe.

Dans votre projet, accédez au répertoire src et apportez les modifications de code suivantes dans le fichier App.jsx.

import { useState } from 'react';
import './App.css';
function App() {
  const [count, setCount] = useState(0);
  return (
    <>
      <h1>Counter App</h1>
      <div className='card'>
        <button onClick={() => setCount((count) => count + 1)}>
          click on me to increase - {count}
        </button>
      </div>
    </>
  );
}

Dans le code ci-dessus, nous avons ajouté un useState accrochez-vous à la fonction App, puis nous avons créé un bouton qui modifie l’état du décompte en appelant setCount lorsque le bouton est cliqué, modifiant ainsi le comportement du App composant.

Le useReducer hook a été introduit comme moyen de gérer des états plus complexes dans une application React. Ainsi, lorsque vous vous retrouvez à suivre plusieurs éléments d’état qui reposent sur une logique complexe dans votre application, useReducer peut être utile.

Dans votre projet, rendez-vous dans le src répertoire et apportez les modifications de code suivantes ci-dessous au App.jsx déposer.

import React, { useReducer } from 'react';
    

const counterReducer = (state, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + 1 };
    case 'DECREMENT':
      return { count: state.count - 1 };
    default:
      return state;
  }
};
    
const CounterApp = () => {
  
  const [state, dispatch] = useReducer(counterReducer, { count: 0 });
    
  return (
    <div>
      <h1>Counter App</h1>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button>
      <button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button>
    </div>
  );
};
    
export default CounterApp; 

Dans le code ci-dessus, nous avons créé un counterReducer fonction qui prend deux paramètres : state et action. Au sein du counter fonction, nous utilisons une instruction switch pour vérifier chaque cas du type d’action, renvoyant une nouvelle valeur qui servira d’état mis à jour pour le useReducerla valeur de l’état. Par la suite, nous avons développé un CounterApp composant utilisant le useReducer hook, qui nécessite deux valeurs : la valeur précédemment définie counterReducer et un counter objet qui stocke l’état.

Le useReducer La fonction fournit l’état actuel chaque fois qu’une action est envoyée, ainsi qu’un dispatch fonction de répartition des actions vers la fonction réducteur. Enfin, nous lions le dispatch fonction à deux boutons différents, chacun associé à un type d’action distinct, un pour l’incrémentation et un pour la décrémentation.

À partir de maintenant, l’interface utilisateur ne changera pas ; tout ce que nous ferons, c’est appliquer différents outils de gestion d’état à cette même application.

Redux

Redux est un outil de gestion d’état populaire dans l’écosystème React ; il suit l’architecture Flux et est également livré avec des outils supplémentaires pour l’optimisation.

Dans votre terminal, exécutez les commandes suivantes pour installer les dépendances Redux et React-Redux.

npm install redux react-redux

Dans votre projet, accédez au répertoire « src » et apportez les modifications de code suivantes au App.jsx fichier ci-dessous.

import { useSelector, useDispatch } from 'react-redux';
import './App.css';
    

const increment = () => ({
  type: 'INCREMENT',
});
const decrement = () => ({
  type: 'DECREMENT',
});
    
function App() {
  const count = useSelector((state) => state.count);
  const dispatch = useDispatch();
  return (
    <>
      <h1>Counter App</h1>
      <div className='card'>
        count {count}
        <div>
          <br />
          <button onClick={() => dispatch(increment())}>Increment</button>
          <span> </span>
          <button onClick={() => dispatch(decrement())}>Decrement</button>
        </div>
      </div>
    </>
  );
}
export default App;

Dans le code ci-dessus, nous importons d’abord useSelector et useDispatch depuis react-redux. Ensuite, nous créons le decrement et increment fonctions qui renvoient un objet avec une clé définie sur type et une valeur définie sur DECREMENT et INCREMENTrespectivement, qui seront distribués, apportant ainsi des modifications au magasin et mettant à jour la vue.

Dans le App fonction, nous appelons useSelector pour sélectionner les données du magasin, qui sont countet useDispatch pour obtenir la fonction de répartition utilisée pour la mise à jour. Enfin, nous attachons le increment et decrement fonctions que nous avons créées précédemment à la fonction de répartition obtenue à partir du useDispatch crochet. Nous transmettons ensuite la fonction de répartition aux boutons individuels qui gèrent l’incrémentation et la décrémentation du count variable.

Dans votre projet, accédez au src répertoire et apportez les modifications de code suivantes au main.jsx déposer.

import React from 'react';
import ReactDOM from 'react-dom/client';
import { legacy_createStore } from 'redux';
import { Provider } from 'react-redux';
import App from './App.jsx';
import './index.css';
    

const initialState = {
  count: 0,
};
const counterReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + 1 };
    case 'DECREMENT':
      return { count: state.count - 1 };
    default:
      return state;
  }
};
const store = legacy_createStore(counterReducer);
ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>

Dans le code ci-dessus, nous avons importé le createStore et Provider de Redux et React-Redux. Nous avons créé la fonction de réduction, qui gère la logique liée à chaque action distribuée.

Ensuite, nous avons initialisé l’état, qui sera défini lors du rendu initial. Au sein du réducteur, nous avons implémenté un cas de commutation qui gère la logique individuelle pour chaque cas, à savoir l’incrémentation et la décrémentation. Étant donné que le réducteur est une fonction pure (respectez toujours les meilleures pratiques en matière de fonction pure pour les réducteurs), la logique de chaque cas est prévisible, ce qui entraîne le retour d’un objet avec des modifications isolées.

Enfin, nous avons créé le magasin et l’avons transmis au Provider composant, qui enveloppe notre racine App composant.

MobX

MobX est un autre outil de gestion d’état qui vous permet de gérer l’état de votre application en dehors d’un cadre d’interface utilisateur (MobX est indépendant du cadre).

Dans votre terminal, exécutez les commandes suivantes pour installer les dépendances MobX et MobX-React.

npm install mobx mobx-react

Dans votre projet, accédez au répertoire « src » et apportez les modifications de code suivantes dans le App.jsx fichier ci-dessous.

import React from 'react';
import ReactDOM from 'react-dom/client';
import { makeAutoObservable } from 'mobx';
import './App.css';
    
class CounterStore {
  count = 0;
  constructor() {
    makeAutoObservable(this);
  }
  increment = () => {
    this.count++;
  };
  decrement = () => {
    this.count--;
  };
}
const counterStore = new CounterStore();
import App from './App.jsx';
import './index.css';
ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App counter={counterStore} />
  </React.StrictMode>
)

Nous avons importé makeAutoObservable à partir de MobX, puis nous avons créé le CounterStore cours avec un counter propriété. Nous avons également créé les méthodes increment et decrement. Nous avons appelé makeAutoObservable dans le CounterStore constructeur pour le rendre observable. Ensuite, nous avons créé un counterStore objet et l’a passé dans le App composant.

Dans votre projet, rendez-vous dans le src répertoire et apportez les modifications de code suivantes dans le main.jsx déposer.

import { observer } from 'mobx-react-lite';
const App = observer(({ counter }) => {
  return (
    <>
      <h1>Counter App</h1>
      <div className='card'>
        count {counter.count}
        <div>
          <br />
          <button onClick={counter.increment}>Increment</button>
          <span> </span>
          <button onClick={counter.decrement}>Decrement</button>
        </div>
      </div>
    </>
  );
});
export default App;

Nous avons importé l’observateur depuis mobx-react-lite. Ensuite, nous avons appelé l’observateur et lui avons transmis une fonction contenant notre composant App JSX, ce qui en fait un observateur d’un observable, par exemple le counterStore que nous avons créé précédemment. Dans la fonction transmise à l’observateur, nous avons déstructuré les accessoires de compteur que nous avons transmis précédemment et attaché les propriétés d’incrémentation et de décrémentation aux boutons d’incrémentation et de décrémentation, respectivement.

Autres solutions de gestion d’état

Zustand est un outil de gestion d’état minimaliste doté d’une API confortable basée sur des hooks. Pour installer la dépendance Zustand, exécutez la commande suivante dans votre terminal :

npm install zustand

Dans votre projet, accédez au src répertoire et apportez les modifications de code suivantes dans le App.jsx fichier ci-dessous.

import { create } from 'zustand';
const useStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
}));
const App = () => {
  const { count, increment, decrement } = useStore();
  return (
    <>
      <h1>Counter App</h1>
      <div className='card'>
        count {count}
        <div>
          <br />
          <button onClick={increment}>Increment</button>
          <span> </span>
          <button onClick={decrement}>Decrement</button>
        </div>
      </div>
    </>
  );
};
export default App;

Nous avons importé create de Zustand, puis nous avons créé un useStore variable qui fait référence à la fonction renvoyée par le create appel de fonction. Une fonction est passée dans le create fonction, qui renvoie un objet comme paramètre. Cette fonction prend un paramètre appelé setque nous utilisons pour créer notre increment et decrement méthodes, contenant la logique pour augmenter et diminuer le counter propriété.

Ensuite, nous avons créé un App fonction qui appelle le useStore fonction et déstructures count, increment et decrement à partir de cela. Enfin, nous avons joint le decrement et increment fonctions à leurs boutons respectifs pour augmenter et diminuer la valeur du compteur.

Dans votre projet, rendez-vous dans le src répertoire et apportez les modifications de code suivantes ci-dessous dans le main.jsx déposer.

import React from 'react';
import ReactDOM from 'react-dom/client';
import './App.css';
import App from './App.jsx';
import './index.css';
ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);    

Dans le code ci-dessus, nous sommes revenus au code par défaut du fichier main.jsx.

L’outil de gestion de l’état Recoil est utilisé pour gérer des états complexes qui ne peuvent pas être obtenus avec React seul.

Dans votre terminal, exécutez les commandes suivantes pour installer la dépendance Recoil.

npm install recoil  

Dans votre projet, accédez au src répertoire et apportez les modifications de code suivantes dans le App.jsx fichier ci-dessous.

import { atom, useRecoilValue, useRecoilState } from 'recoil';
import './App.css';
    
const counterState = atom({
  key: 'counterState', 
  default: 0, 
});
    
const App = () => {
  const count = useRecoilValue(counterState);
  const [countState, setCountState] = useRecoilState(counterState);
  const increment = () => {
    setCountState(countState + 1);
  };
  const decrement = () => {
    setCountState(countState - 1);
  };
    
  return (
    <>
      <h1>Counter App</h1>
      <div className='card'>
        count {count}
        <div>
          <br />
          <button onClick={increment}>Increment</button>
          <span> </span>
          <button onClick={decrement}>Decrement</button>
        </div>
      </div>
    </>
  );
};
export default App 

Nous avons importé le atom, useRecoilValue et useRecoilState du recul. Ensuite, nous avons créé un counterState variable pour contenir l’état que nous allons modifier. Nous avons ensuite défini un App fonction qui appelle useRecoilValue avec le counterState nous avons créé plus tôt, qui renvoie la valeur de comptage. Nous avons également appelé useRecoilState avec le counterState variable, qui renvoie le counterState et setCounterState.

Par la suite, nous avons créé des fonctions d’incrémentation et de décrémentation qui appellent setCounterState avec la logique des changements souhaités. Enfin, nous avons attaché les fonctions d’incrémentation et de décrémentation à leurs boutons respectifs pour augmenter et diminuer le compteur.

Il convient de noter que useRecoilState est utilisé pour lire et écrire des atomes, tandis que useRecoilValue est utilisé uniquement pour lire les atomes. Par conséquent, si les composants doivent lire un atome sans y écrire, ils doivent utiliser useRecoilValue.

Dans votre projet, accédez au src répertoire et apportez les modifications de code suivantes dans le main.jsx déposer.

import React from 'react';
import ReactDOM from 'react-dom';
import { RecoilRoot } from 'recoil';
import App from './App';
    
ReactDOM.render(
  <RecoilRoot>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </RecoilRoot>,
 document.getElementById('root')
);  

Dans ce code, nous avons importé le RecoilRootqui fournit le contexte dans lequel les atomes ont des valeurs, puis l’a enveloppé autour de notre composant racine App.

Jotai est un outil de gestion d’état orienté TypeScript avec une API très minimaliste.

Dans votre terminal, exécutez les commandes suivantes pour installer la dépendance Jotai.

npm install jotai 

Dans votre projet, accédez au src répertoire et apportez les modifications de code suivantes dans le main.jsx fichier ci-dessous.

import React from 'react';
import { Provider } from 'jotai';
import ReactDOM from 'react-dom/client';
import App from './App.jsx';
import './index.css';
    ReactDOM.createRoot(document.getElementById('root')).render(
  <Provider>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </Provider>
);

Dans le code ci-dessus, nous avons importé le fournisseur de Jotai, qui fournit le contexte à partir duquel les valeurs atomiques du sous-arbre des composants sont disponibles. Nous avons ensuite enveloppé notre composant d’application racine avec.

Dans votre projet, rendez-vous dans le src et apportez les modifications de code suivantes dans le fichier App.jsx.

import { atom, useAtom } from 'jotai';
import './App.css';
    
const counterAtom = atom(0);
    
const App = () => {
  const [count, setCount] = useAtom(counterAtom);
  const increment = () => {
   setCount(count + 1);
  };
  const decrement = () => {
    setCount(count - 1);
  };
  return (
    <>
      <h1>Counter App</h1>
      <div className='card'>
        count {count}
        <div>
         <br />
          <button onClick={increment}>Increment</button>
          <span> </span>
          <button onClick={decrement}>Decrement</button>
        </div>
      </div>
    </>
  );
};
export default App;

Dans le code ci-dessus, nous avons créé notre counterAtom variable, qui contient notre valeur atomique. Ensuite, nous avons créé un App fonction qui appelle le useAtom fonction, qui prend counterAtom comme valeur et renvoie une variable pour lire la valeur de l’atome et une fonction pour modifier sa valeur.

Par la suite, nous avons créé le decrement et increment fonctionne avec la logique pour diminuer et augmenter la valeur de comptage. Enfin, nous avons attaché les fonctions à leurs boutons respectifs pour augmenter et diminuer la valeur de comptage.

Conclusion

L’écosystème React offre un large éventail d’options pour implémenter la gestion de l’état, allant du simple hook useState à des solutions plus complexes comme Redux. Cependant, l’objectif principal de chaque développeur est de choisir le bon outil pour son projet. Cette décision doit être basée sur votre familiarité avec l’outil, sa courbe d’apprentissage et son évolutivité. En fin de compte, lorsqu’il s’agit de gestion de l’état dans votre projet, l’écosystème React est là pour vous.




Source link