Comment démarrer avec Redux pour la gestion de l'état JavaScript

0
205

Redux est un outil de gestion d'état, conçu spécifiquement pour les applications JavaScript côté client qui dépendent fortement de données complexes et des API externes et fournit d'excellents outils de développement qui facilitent le travail avec vos données.

Que fait Redux ?

Simplement mis, Redux est un magasin de données centralisé. Toutes vos données d'application sont stockées dans un seul objet volumineux. Les outils de développement Redux facilitent la visualisation :

Cet état est immuable, ce qui est un concept étrange au début, mais qui a du sens pour plusieurs raisons. Si vous souhaitez modifier l'état, vous devez envoyer une action, qui prend essentiellement quelques arguments, forme une charge utile et l'envoie à Redux. Redux transmet l'état actuel à une fonction de réduction, qui modifie l'état existant et renvoie un nouvel état qui remplace l'état actuel et déclenche un rechargement des composants affectés. Par exemple, vous pouvez avoir un réducteur pour ajouter un nouvel élément à une liste, ou supprimer ou modifier un élément qui existe déjà.

En procédant de cette façon, vous n'obtiendrez jamais de comportement indéfini avec l'état de modification de votre application à volonté. De plus, parce qu'il y a un enregistrement de chaque action et de ce qu'il a changé, il permet le débogage dans le temps, où vous pouvez faire défiler l'état de votre application pour déboguer ce qui se passe avec chaque action (un peu comme un historique git).

Redux peut être utilisé avec n'importe quel framework frontal, mais il est couramment utilisé avec React, et c'est ce sur quoi nous allons nous concentrer ici. Sous le capot, Redux utilise l'API de contexte de React, qui fonctionne de la même manière que Redux et convient aux applications simples si vous souhaitez renoncer complètement à Redux. Cependant, les Devtools de Redux sont fantastiques lorsque vous travaillez avec des données complexes, et ils sont en fait plus optimisés pour éviter les rendus inutiles.

Publicité

Si vous utilisez TypeScript, les choses sont beaucoup plus compliquées pour que Redux soit strictement typé. Vous souhaiterez plutôt suivre ce guide, qui utilise typesafe-actions pour gérer les actions et les réducteurs de manière conviviale.

Structurer Votre projet

Tout d'abord, vous souhaiterez disposer la structure de vos dossiers. Cela dépend de vous et des préférences de style de votre équipe, mais il existe essentiellement deux modèles principaux que la plupart des projets Redux utilisent. La première consiste simplement à diviser chaque type de fichier (action, réducteur, middleware, effet secondaire) dans son propre dossier, comme suit :

store/actions/reducers/sagas/middleware/index.js

Ce n'est cependant pas le meilleur, car vous aurez souvent besoin d'un fichier d'action et d'un fichier de réduction pour chaque fonctionnalité que vous ajoutez. Il est préférable de fusionner les dossiers d'actions et de réducteurs et de les diviser par fonctionnalité. De cette façon, chaque action et le réducteur correspondant se trouvent dans le même fichier. Vous

stockez/features/todo/etc/sagas/middleware/root-reducer.js root-action.js index.js

Cela nettoie les importations, car vous pouvez désormais importer à la fois les actions et les réducteurs dans la même instruction en utilisant :

import { todosActions, todosReducer } from 'store/features/todos'

C'est à vous de décider si vous souhaitez conserver le code Redux dans son propre dossier (/store dans les exemples ci-dessus) ou l'intégrer dans le dossier src racine de votre application. Si vous séparez déjà le code par composant et que vous écrivez de nombreuses actions et réducteurs personnalisés pour chaque composant, vous souhaiterez peut-être fusionner les dossiers /features/et /components/ et stocker les composants JSX avec le code du réducteur.< /p>

Si vous utilisez Redux avec TypeScript, vous pouvez ajouter un fichier supplémentaire dans chaque dossier de fonctionnalités pour définir vos types.

Installation et configuration de Redux

Installez Redux et React-Redux à partir de NPM :

npm install redux react-redux

Vous voudrez probablement aussi redux-devtools :

npm install –save-dev redux-devtools

La première chose que vous voudrez créer est votre magasin. Enregistrez-le sous /store/index.js

import { createStore } depuis 'redux' importez rootReducer depuis './root-reducer' const store = createStore(rootReducer) exportez le magasin par défaut ; Publicité

Bien sûr, votre magasin deviendra plus compliqué que cela à mesure que vous ajouterez des éléments tels que des modules complémentaires d'effets secondaires, des middleware et d'autres utilitaires tels que le routeur de réaction connecté, mais c'est tout ce qui est requis pour le moment. Ce fichier utilise le réducteur racine et appelle createStore() à l'aide de celui-ci, qui est exporté pour que l'application puisse l'utiliser.

Ensuite, nous allons créer une simple fonctionnalité de liste de tâches. Vous voudrez probablement commencer par définir les actions requises par cette fonctionnalité et les arguments qui leur sont transmis. Créez un dossier /features/todos/ et enregistrez les éléments suivants sous types.js :

export const ADD = 'ADD_TODO' export const DELETE = 'DELETE_TODO' export const EDIT = 'EDIT_TODO'

Cela définit quelques constantes de chaîne pour les noms d'action. Quelles que soient les données que vous transmettez, chaque action aura une propriété de type, qui est une chaîne unique qui identifie l'action.

Vous n'êtes pas obligé d'avoir un fichier de type comme celui-ci, car vous pouvez simplement taper le nom de chaîne de l'action, mais il est préférable pour l'interopérabilité de procéder de cette façon. Par exemple, vous pourriez avoir todos.ADD et rappelles.ADD dans la même application, ce qui vous évite d'avoir à saisir _TODO ou _REMINDER chaque fois que vous faites référence à une action pour cette fonctionnalité.

Ensuite, enregistrez ce qui suit as /store/features/todos/actions.js :

import * as types from './types.js' export const addTodo = text => ({ type : types.ADD, text }) export const deleteTodo = id => ({ type : types.DELETE, id }) export const editTodo = (id, text) => ({ tapez : types.EDIT, identifiant, texte })

Cela définit quelques actions utilisant les types des constantes de chaîne, exposant les arguments et la création de charge utile pour chacun. Celles-ci n'ont pas besoin d'être entièrement statiques, car ce sont des fonctions, un exemple que vous pouvez utiliser est la définition d'un CUID d'exécution pour certaines actions.

Publicité

La partie la plus compliquée de code, et où vous implémenterez la plupart de votre logique métier, se trouve dans les réducteurs. Celles-ci peuvent prendre de nombreuses formes, mais la configuration la plus couramment utilisée consiste à utiliser une instruction switch qui gère chaque cas en fonction du type d'action. Enregistrez-le sous le nom reducer.js :

import * as types from './types.js' const initialState = [ { text: 'Hello World', id: 0 } ] export default function todos(state = initialState, action) { switch (action.type) { case types .ADD: return [ …state, { id: state.reduce((maxId, todo) => Math.max(todo.id, maxId), -1) + 1, text: action.text } ] case types.DELETE: return state.filter(todo => todo.id !== action.id ) case types.EDIT: return state.map(todo => todo.id === action.id ? { .. .todo, text : action.text } : todo ) par défaut : return state } }

L'état est passé en argument et chaque cas renvoie une version modifiée de l'état. Dans cet exemple, ADD_TODO ajoute un nouvel élément à l'état (avec un nouvel ID à chaque fois), DELETE_TODO supprime tous les éléments avec l'ID donné, et EDIT_TODO mappe et remplace le texte de l'élément avec l'ID donné.

< p>L'état initial doit également être défini et transmis à la fonction de réduction comme valeur par défaut pour la variable d'état. Bien sûr, cela ne définit pas l'intégralité de votre structure d'état Redux, seulement la section state.todos.

Ces trois fichiers sont généralement séparés dans des applications plus complexes, mais si vous le souhaitez, vous pouvez également définir tous dans un seul fichier, assurez-vous simplement que vous importez et exportez correctement.

Une fois cette fonctionnalité terminée, connectons-la à Redux (et à notre application). Dans /store/root-reducer.js, importez le todosReducer (et tout autre réducteur de fonctionnalités à partir du dossier /features/ ), puis transmettez-le à combineReducers(), formant un réducteur racine de niveau supérieur qui est transmis au magasin. C'est ici que vous configurerez l'état racine, en vous assurant de conserver chaque fonctionnalité sur sa propre branche.

import { combineReducers } from 'redux'; importer todosReducer depuis './features/todos/reducer' ; const rootReducer = combineReducers({ todos: todosReducer }) export rootReducer par défaut

Utilisation de Redux In React

Bien sûr, rien de tout cela n'est utile s'il n'est pas connecté à React. Pour ce faire, vous devrez envelopper l'intégralité de votre application dans un composant fournisseur. Cela garantit que l'état et les hooks nécessaires sont transmis à chaque composant de votre application.

Publicité

Dans App.js ou index.js, partout où vous avez votre fonction de rendu racine, encapsulez votre application dans un <Provider>, et transmettez-lui le magasin (importé de /store/index.js) en tant qu'accessoire :

importer React de 'react' ; importer ReactDOM de 'react-dom' ; // Redux Setup importer { Provider } de 'react-redux' ; importer store, { history } from './store' ; ReactDOM.render(     <Provider store={store}> <App/>     </Provider>     , document.getElementById('root'));

Vous êtes maintenant libre d'utiliser Redux dans vos composants. La méthode la plus simple consiste à utiliser des composants de fonction et des crochets. Par exemple, pour envoyer une action, vous utiliserez le crochet useDispatch(), qui vous permet d'appeler directement des actions, par ex. dispatch(todosActions.addTodo(text)).

Le conteneur suivant a une entrée connectée à l'état React local, qui est utilisé pour ajouter une nouvelle tâche à l'état chaque fois qu'un bouton est cliqué :

importer React, { useState } de 'react' ; importer './Home.css' ; importer { TodoList } de ' ' composants' importer { todosActions } de ' 'store/features/todos' importer { useDispatch } de ' react-redux' function Home() {   const dispatch = useDispatch(); const [text, setText] = useState(“”); function handleClick() {     dispatch(todosActions.addTodo(text)); Définir le texte(“”); }   function handleChange(e : React.ChangeEvent<HTMLInputElement>) {     setText(e.target.value); }   return (     <div className=”App”>       <header className=”App-header”>         <input type=”text” value={text} onChange={handleChange} ; /& gt;     ={handleClick}>           Ajouter une nouvelle tâche         </button>         <TodoList />       </header>     </div>  } exporter la page d'accueil par défaut ;

Ensuite, lorsque vous souhaitez utiliser les données stockées dans l'état, utilisez le crochet useSelector. Cela prend une fonction qui sélectionne une partie de l'état à utiliser dans l'application. Dans ce cas, il définit la variable de publication sur la liste actuelle des tâches. Ceci est ensuite utilisé pour afficher un nouvel élément de tâche pour chaque entrée dans state.todos.

import React from 'react' ; import { useSelector } from 'store' import { Container, List, ListItem, Title } from './styles' function TodoList() {   const posts = useSelector(state => state.todos)  & return         &lt List>         {posts.map(({ id, title }) => (           <ListItem key={title}>              <Title>{title} : {id}< )}       </List>     </Container>   ); } exporter la liste de tâches par défaut ;

Vous pouvez réellement créer des fonctions de sélection personnalisées pour gérer cela pour vous, enregistrées dans le dossier /features/ un peu comme des actions et des réducteurs.

Une fois que vous avez tout configuré et compris, vous voudrez peut-être examinez la configuration de Redux Devtools, la configuration d'un middleware comme Redux Logger ou un routeur réactif connecté, ou l'installation d'un modèle d'effet secondaire tel que Redux Sagas.