Vous êtes sur la page 1sur 12

I. Complexité de gestion de l'état avant l'adoption de Redux.

Avant d'introduire Redux, il est important de comprendre la problématique qu'il vise à résoudre
dans le contexte du développement d'applications front-end, notamment avec des bibliothèques
comme React.

La gestion de l'état dans une application web devient rapidement complexe à mesure que
l'application grandit en taille et en complexité. Dans une application React typique, l'état est
souvent géré au niveau des composants. Cependant, lorsque plusieurs composants ont besoin
d'accéder et de modifier le même état, cela peut entraîner des problèmes de synchronisation, de
compréhension du flux de données, et de maintenance.

Proposons une interface de notre application, qu’on veut réaliser. On présente ici les différents
composants qu’on peut déclarer.

Résumant le dom de notre application :

Avant Redux, la gestion de l'état dans une application React impliquait souvent le passage des données
entre les composants via les "props" (propriétés). Cependant, cela pouvait devenir complexe lorsque
plusieurs composants imbriqués avaient besoin d'accéder ou de modifier le même état, entraînant une
cascade de "props drillings" (passage de propriétés) pour transmettre les données à travers différents
P a g e 1 | 12
niveaux de composants. Redux simplifie ce processus en centralisant l'état dans un store global,
réduisant ainsi la nécessité de propager manuellement les données à travers la hiérarchie des
composants.

Voici quelques problèmes courants liés à la gestion de l'état dans les applications React avant
l'introduction de Redux :

1. Passage de données entre composants : Lorsqu'un état doit être partagé entre plusieurs composants
qui ne sont pas directement liés par une relation parent-enfant, le passage des données peut devenir
compliqué.
2. Gestion de l'état partagé : Lorsque l'état doit être partagé entre des composants profonds dans la
hiérarchie des composants, la gestion de cet état devient difficile sans mécanisme centralisé.
3. Rendre les composants moins prévisibles : Si les données sont modifiées à différents endroits de
l'application sans qu'il y ait une trace claire de ces modifications, cela peut rendre le comportement
de l'application moins prévisible et plus difficile à déboguer.
4. Difficulté à comprendre le flux de données : Comprendre comment les données circulent à travers
l'application peut devenir déroutant, surtout lorsque plusieurs composants interagissent avec le même
état.

Exemple 1 : l’ajout d’un article qui contient le titre du post et son contenu, ci-dessous
l’interface de notre application :

P a g e 2 | 12
Proposition de correction :

Article.js : Composant React pour afficher un article. - Reçoit un article en tant que prop et affiche
son titre et son contenu.
import React from "react"
const article = ({ article }) => (
<div className="article">
<h1>{article.title}</h1>
<p>{article.body}</p>
</div>
)
export default article
AddArticle.js : Composant React définissant le formulaire pour ajouter un nouvel article.
- Utilise le hook useState pour gérer l'état local de l'article.
- Les fonctions handleArticleData et addNewArticle gèrent les modifications de l'état et la
soumission du formulaire.
- Les données de l'article sont transmises au composant parent via la fonction saveArticle.

import React, { useState } from "react";

const AddArticle = ({ saveArticle }) => {


const [article, setArticle] = useState({
title: "",
body: "",
});

const handleArticleData = (e) => {


setArticle({
...article,
[e.target.id]: e.target.value,
});
};

P a g e 3 | 12
const addNewArticle = (e) => {
e.preventDefault();
saveArticle(article);
};

return (
<form onSubmit={addNewArticle} className="add-article">
<input
type="text"
id="title"
placeholder="Title"
onChange={handleArticleData}
/>
<input
type="text"
id="body"
placeholder="Body"
onChange={handleArticleData}
/>
<button>Add article</button>
</form>
);
}; export default AddArticle;

Le composant App rend le composant Articles.

App.js

import React from "react"


import Articles from "./containers/Articles"
function App() {
return <Articles />
}
export default App
Le composant Articles est connecté à Redux et utilise le store pour afficher la liste initiale
d'articles.
Articles.js
import React from "react"
import { connect } from "react-redux"
import Article from "../components/Article"
import AddArticle from "../components/AddArticle"
import { addArticle } from "../store/actionCreators"
const Articles = ({ articles, saveArticle }) => (
<div>
<AddArticle saveArticle={saveArticle} />
{articles.map(article => (
<Article key={article.id} article={article} />
))}
</div>
)
const mapStateToProps = state => {
return {
P a g e 4 | 12
articles: state.articles,
} }
const mapDispatchToProps = dispatch => {
return {
saveArticle: article => dispatch(addArticle(article)),
} }
export default connect(mapStateToProps, mapDispatchToProps)(Articles)

reducer.js

import * as actionTypes from "./actionTypes";

const initialState = {
articles: [
{ id: 1, title: "post 1", body: "Quisque cursus, metus vitae pharetra" },
{ id: 2, title: "post 2", body: "Quisque cursus, metus vitae pharetra" },
],
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case actionTypes.ADD_ARTICLE:
return {
...state,
articles: [...state.articles, action.article],
};
default:
return state; } };export default reducer;

Le composant Articles rend également le composant AddArticle, qui est un formulaire permettant à
l'utilisateur d'ajouter un nouvel article.

Interaction Utilisateur :
 L'utilisateur remplit les champs du formulaire (AddArticle.js) avec un titre et un contenu.
 Lorsque l'utilisateur clique sur le bouton "Add article", le formulaire déclenche la fonction
saveArticle.
Action Redux :
 La fonction saveArticle crée une action Redux (addArticle) avec les données du nouvel article.
 Cette action est ensuite envoyée au store Redux via la fonction dispatch.
actionCreators.js
import * as actionTypes from "./actionTypes"
export const addArticle = article => {
return {
type: actionTypes.ADD_ARTICLE,
article,} }
Traitement de l'Action par le Reducer :
 Le reducer (reducer.js) détecte l'action de type ADD_ARTICLE.
actionTypes.js
export const ADD_ARTICLE = "ADD_ARTICLE"
 Il crée un nouvel état en ajoutant le nouvel article à la liste existante d'articles.

P a g e 5 | 12
Mise à Jour de l'État :
 Le store Redux met à jour son état avec le nouvel état généré par le reducer.
Réaffichage de la Liste d'Articles :
 Le composant Articles (connecté au store) détecte le changement d'état et se réaffiche automatiquement
avec la liste mise à jour d'articles, y compris le nouvel article ajouté.
Index.js : La page charge le point d'entrée de l'application (index.js), qui configure le store Redux et
rend le composant racine App.

import React from 'react';


import ReactDOM from 'react-dom/client';
import App from './App';
import { createStore } from "redux"//ou import { legacy_createStore } from 'redux';
import { Provider } from "react-redux"
import reducer from "./store/reducer"
const store = createStore(reducer)
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Provider store={store}>
<App /></Provider>);

Nouvelle manière de code :

Il y a une version de l'application en utilisant les hooks useDispatch et useSelector, sans la nécessité
du principe connect.
Avec cette approche, la connectivité Redux est gérée directement dans les composants à l'aide des
hooks, éliminant la nécessité du principe connect et des conteneurs séparés. Vous pouvez regrouper
les actions et le reducer dans un dossier store pour maintenir une structure bien organisée.
La distinction traditionnelle entre composants et conteneurs était plus significative lorsqu'on utilisait la
connectivité Redux avec la fonction connect. Les conteneurs étaient utilisés pour connecter les
composants à Redux. Cependant, avec l'approche moderne utilisant des hooks, cette distinction devient
moins nécessaire.
Ainsi, votre structure de fichiers peut être simplifiée sans le dossier containers. Les composants peuvent
directement utiliser des hooks pour accéder au store Redux. Vous pouvez organiser vos fichiers en
fonction de la logique métier et des fonctionnalités, en regroupant les composants liés et les
fonctionnalités associées dans des dossiers pertinents.
Remarques :
 useDispatch remplace la nécessité de la fonction mapDispatchToProps avec connect. Vous obtenez
simplement le dispatch directement.
 useSelector remplace la nécessité de la fonction mapStateToProps. Il vous permet de sélectionner
directement des parties du state dont votre composant a besoin.
 Ces changements rendent le code plus concis et évitent la surcharge de connect et
mapStateToProps/mapDispatchToProps.

P a g e 6 | 12
1. Composant : Les composants React envoient des actions au store pour déclencher des
changements d'état.
2. Dispatcher, Action, Reducer: Le dispatcher réceptionne les actions émises par les
composants et les transmet aux reducers. Les reducers spécifient comment l'état de
l'application doit changer en réponse à ces actions.
3. State et Store: Le state de l'application est stocké de manière centralisée dans le store, qui
met à jour automatiquement les composants écoutant les changements d'état, assurant ainsi
une gestion claire et prévisible de l'état dans toute l'application.
Voilà une proposition d’architecture des fichiers selon le nouveau code :

index.js App.js
import React from 'react'; import React from "react";
import ReactDOM from 'react-dom/client'; import Articles from
import App from './App'; "./components/Articles";
import { createStore } from "redux"
//ou import { legacy_createStore } from 'redux'; function App() {
import { Provider } from "react-redux" return (
P a g e 7 | 12
import reducer from "./store/reducer" <div>
const store = createStore(reducer) <h1>Redux Blog</h1>
const root = <Articles />
ReactDOM.createRoot(document.getElementById('root')); </div>
root.render( );
<Provider store={store}> }
<App />
</Provider> export default App;
);
Le composant App fait appeler l’autre composant Articles
Articles.js actions.js
import React from "react";
import { useSelector } from "react-redux"; export const ADD_ARTICLE =
import Article from "./Article"; "ADD_ARTICLE";
import AddArticle from "./AddArticle";
export const addArticle = article
const Articles = () => { => ({ type: ADD_ARTICLE,
const articles = useSelector(state => article,
state.articles); });

return (
<div>
<AddArticle />
{articles.map(article => (
<Article key={article.id}
article={article} />))}
</div>); }; export default Articles;
useSelector est un hook fourni par React Redux, et il sert à extraire des données du store Redux dans
un composant React.
Dans cette ligne spécifique, le composant utilise useSelector pour obtenir la liste des articles du store
Redux (state.articles) à travers le reducer (initialState) et stocke ces articles dans la variable
articles.
reducer.js :
import { ADD_ARTICLE } from "./actions";
const initialState = {
articles: [
{ id: 1, title: "post 1", body: "Quisque cursus, metus vitae pharetra" },
{ id: 2, title: "post 2", body: "Quisque cursus, metus vitae pharetra" } ]
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case ADD_ARTICLE:
return {
...state,
articles: [...state.articles, action.article],};
default:
return state;
}
};export default reducer;

P a g e 8 | 12
Dans le composant Articles.js, on ne demande pas seulement l’initialisation de la liste des articles, mais
aussi l’appel du composant AddArticle.js afin de proposer à l’utilisateur d’ajouter un autre article.
AddArticle.js
import React, { useState } from "react";
import { useDispatch } from "react-redux";
import { addArticle } from "../store/actions";

const AddArticle = () => {


const dispatch = useDispatch();
const [article, setArticle] = useState({ title: "", body: "" });

const handleArticleData = e => {


setArticle({
...article,
[e.target.id]: e.target.value
});
};

const addNewArticle = e => {


e.preventDefault();
dispatch(addArticle(article));
};

return (
<form onSubmit={addNewArticle} className="add-article">
<input
type="text"
id="title"
placeholder="Title"
onChange={handleArticleData}
/>
<input
type="text"
id="body"
placeholder="Body"
onChange={handleArticleData}
/>
<button>Add article</button>
</form>
);
};
export default AddArticle;
Ici à l’aide de cette ligne : dispatch(addArticle(article)), fait appel à l’action addArticle,
puis une autre fois on va aller au reducer qui récupère la nouvelle state après l’ajout du nouveau
article.
Finalement il y aura une mise à Jour du Store (Articles.js):
 Le composant Articles.js, grâce au hook useSelector, détecte que le store a été mis à jour.
 Il récupère la nouvelle liste d'articles mise à jour depuis le store.
 Le composant est automatiquement re-rendu avec la nouvelle liste d'articles, incluant le nouvel article
ajouté.

P a g e 9 | 12
Exemple 2 : Incrémenter, décrémenter et mettre à zero un nombre x.

Ici nous n’avons qu’un seul composant qui fait appeler le store :
App.js

import { useSelector, useDispatch } from 'react-redux';


import * as actions from './store/action';
function App() {
const num = useSelector(state => state.num);
const dispatch = useDispatch();
return (<>
<h2>La valeur de x est {num}</h2>
<div>
<button onClick={() =>
dispatch(actions.Incrementer())}>Incrémenter</button>
<button onClick={() =>
dispatch(actions.Decrementer())}>Décrémenter</button>
<button onClick={() => dispatch(actions.Reset())}>Reset</button>
</div> </> );
} export default App;

action.js reducer.js
export const Incrementer = () const initialeState = {num:0}
=> { const reducer = (state = initialeState,
return {type:"Incrementer"} action) => {
} switch(action.type) {
export const Decrementer = () case 'Incrementer':
=> { return {...state, num:state.num+1}
return {type:"Decrementer"} case 'Decrementer':
} return {...state, num:state.num-1}
export const Reset = () => { case 'Reset':
return {type:"Reset"} return {...state, num:0}
} default: return state
} } export default reducer
index.js:

import React from 'react';


import ReactDOM from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';
import { createStore } from "redux"
//ou import { legacy_createStore } from 'redux';
import reducer from './store/reducer';
const store = createStore(reducer)
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render( <Provider store={store}> <App /> </Provider> );

P a g e 10 | 12
L’installation de Redux DevTools
Permet à un développeur de créer, tester et déboguer votre application qui utilise Redux.
L'installation de Redux DevTools dépend du navigateur que vous utilisez. Voici un guide général pour
les navigateurs les plus courants :
Pour Google Chrome :
1. Allez sur la page des extensions Chrome : Chrome Web Store.
2. Recherchez "Redux DevTools" dans la barre de recherche.
3. Trouvez l'extension "Redux DevTools" dans les résultats de la recherche.
4. Cliquez sur "Ajouter à Chrome" pour installer l'extension.
5. Une fois installée, vous devriez voir l'icône de Redux DevTools dans la barre d'outils de Chrome.
Pour Mozilla Firefox :
1. Allez sur la page des modules complémentaires Firefox : Mozilla Add-ons.
2. Recherchez "Redux DevTools" dans la barre de recherche.
3. Trouvez l'extension "Redux DevTools" dans les résultats de la recherche.
4. Cliquez sur "Ajouter à Firefox" pour installer l'extension.
5. Une fois installée, vous devriez voir l'icône de Redux DevTools dans la barre d'outils de Firefox.
Pour Microsoft Edge :
Microsoft Edge prend désormais en charge les extensions Chrome. Vous pouvez suivre les
étapes d'installation pour Chrome mentionnées ci-dessus.
Utilisation dans votre application React avec Redux :
1. Installez l'extension Redux DevTools pour votre navigateur.
2. Assurez-vous que votre application React Redux utilise l'extension. Vous pouvez le faire lors de la
configuration du store Redux.
3. Ajouter ce changement au fichier index.js :
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';
import { createStore } from "redux"
//ou import { legacy_createStore } from 'redux';
import reducer from './store/reducer';
const store = createStore(reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__())
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render( <Provider store={store}> <App /> </Provider> );
L'utilisation de window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__() permet à Redux DevTools de s'intégrer avec
votre application si l'extension est installée.

P a g e 11 | 12
Redux Toolkit

Il est conçu pour simplifier la configuration de Redux et rendre le code plus concis en
fournissant des utilitaires intégrés. Redux Toolkit est une librairie qui facilite la gestion de
l'état dans les applications React avec Redux. Développée pour rendre l'utilisation de Redux
plus simple, plus concise et plus agréable, en fournissant des utilitaires prédéfinis pour certaines
tâches courantes.

Voici un parmi plusieurs avantages de Redux Toolkit par rapport à une configuration manuelle
de Redux :

- Redux Toolkit propose createSlice, une fonction qui combine la définition du reducer et des
actions associées en un seul endroit. Cela réduit considérablement la quantité de code nécessaire
pour gérer l'état dans le store.

Cependant, si votre application est relativement simple et que vous êtes à l'aise avec la
configuration manuelle de Redux, vous pouvez toujours choisir de le faire sans Redux Toolkit.
C'est une question de préférence et de contexte spécifique à chaque projet.

pour utiliser Redux Toolkit, vous devez l'installer dans votre projet. Vous pouvez le faire en
utilisant npm ou yarn. Voici comment vous pouvez l'installer avec npm :

npm install @reduxjs/toolkit react-redux

@reduxjs/toolkit est le paquet contenant Redux Toolkit, et react-redux est utilisé pour intégrer
Redux avec React.

Après l'installation, vous pouvez commencer à utiliser les fonctionnalités de Redux Toolkit,
telles que createSlice et configureStore, dans votre application React.

P a g e 12 | 12

Vous aimerez peut-être aussi