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.
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 useReducer
la 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 INCREMENT
respectivement, 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 count
et 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é set
que 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 RecoilRoot
qui 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