Pourquoi Redux avec React : guide complet ?
Dans le monde moderne du développement web, React a rapidement gagné la reconnaissance en tant que bibliothèque de rendu frontale populaire. Cependant, lorsque les applications React deviennent plus complexes et nécessitent une gestion étendue de l'état, il est nécessaire d'utiliser un outil comme Redux. Redux permet de centraliser le state de l'application dans un seul magasin (store), ce qui rend l'état facilement accessible, prévisible et gérable.
Un cas concret où Redux serait utile est une application de gestion des tâches. Imaginez que vous ayez une liste de tâches à accomplir, chacune ayant des états différents comme "en cours", "terminée" ou "à faire". Avec React seul, vous pourriez avoir une structure d'état complexe et difficile à maintenir, tout en perdant le bénéfice du rendu virtuel de React. C'est là que Redux entre en jeu, facilitant la gestion de l'état global de votre application.
Prerequis
- Connaissance avancée de JavaScript ES6+
- Compréhension des concepts de base de React (components, props, state)
- Familiarité avec les outils de développement frontend (npm, yarn)
Outils à installer :
npm install redux react-redux @reduxjs/toolkit
Concepts fondamentaux
- Store : Ce est le magasin global qui stocke l'état de l'application.
- Actions : Ce sont des objets qui décrivent les événements qui ont eu lieu dans l'application.
- Reducers : Ce sont des fonctions qui prennent l'état actuel et une action, puis retournent le nouvel état.
- Dispatch : Cette méthode est utilisée pour envoyer une action au store.
// Store.js
import { createStore } from 'redux';
import rootReducer from './reducers';
const store = createStore(rootReducer);
export default store;
- Provider : Ce composant de React Redux fournit le store à l'ensemble de votre application.
- Connect : Cette fonction permet d'accéder au state et aux dispatchs depuis un component.
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './App';
import store from './store';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
Mise en pratique : projet fil rouge
Nous allons créer un simple gestionnaire de tâches avec Redux. Le but est d'ajouter, supprimer et marquer comme terminée les tâches.
Étape 1 : Création du projet
npx create-react-app task-manager-redux
cd task-manager-redux
Étape 2 : Configuration de Redux
Créer un fichier store.js dans le dossier src.
// src/store.js
import { createStore } from 'redux';
const initialState = {
tasks: []
};
function rootReducer(state = initialState, action) {
switch (action.type) {
case 'ADD_TASK':
return {
...state,
tasks: [...state.tasks, action.payload]
};
case 'DELETE_TASK':
return {
...state,
tasks: state.tasks.filter(task => task.id !== action.payload)
};
case 'TOGGLE_TASK':
return {
...state,
tasks: state.tasks.map(task =>
task.id === action.payload ? { ...task, completed: !task.completed } : task
)
};
default:
return state;
}
}
const store = createStore(rootReducer);
export default store;
Étape 3 : Création des Actions
Créer un fichier actions.js dans le dossier src.
// src/actions.js
export const addTask = (task) => ({
type: 'ADD_TASK',
payload: task
});
export const deleteTask = (id) => ({
type: 'DELETE_TASK',
payload: id
});
export const toggleTask = (id) => ({
type: 'TOGGLE_TASK',
payload: id
});
Étape 4 : Création des Components
Créer un fichier TaskList.js dans le dossier src.
// src/TaskList.js
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { deleteTask, toggleTask } from './actions';
const TaskList = () => {
const tasks = useSelector(state => state.tasks);
const dispatch = useDispatch();
return (
<ul>
{tasks.map(task => (
<li key={task.id}>
<input
type="checkbox"
checked={task.completed}
onChange={() => dispatch(toggleTask(task.id))}
/>
{task.text}
<button onClick={() => dispatch(deleteTask(task.id))}>Delete</button>
</li>
))}
</ul>
);
};
export default TaskList;
Créer un fichier App.js pour utiliser le component.
// src/App.js
import React from 'react';
import { useDispatch } from 'react-redux';
import { addTask } from './actions';
import TaskList from './TaskList';
const App = () => {
const dispatch = useDispatch();
const handleAddTask = (event) => {
event.preventDefault();
const taskText = document.getElementById('task-input').value;
if (taskText.trim()) {
dispatch(addTask({ id: Date.now(), text: taskText, completed: false }));
document.getElementById('task-input').value = '';
}
};
return (
<div>
<h1>Task Manager</h1>
<form onSubmit={handleAddTask}>
<input type="text" id="task-input" placeholder="New Task" />
<button type="submit">Add Task</button>
</form>
<TaskList />
</div>
);
};
export default App;
Erreurs frequentes et debugging
Erreur :
Uncaught TypeError: Cannot read property 'map' of undefined// ❌ Mauvais const tasks = useSelector(state => state.tasks); return ( <ul> {tasks.map(task => ( // Erreur si tasks est undefined <li key={task.id}>{task.text}</li> ))} </ul> ); javascript // ✅ Correct const tasks = useSelector(state => state.tasks || []); return ( <ul> {tasks.map(task => ( <li key={task.id}>{task.text}</li> ))} </ul> );Erreur :
Uncaught Error: Actions must be plain objects.// ❌ Mauvais dispatch({ type: 'ADD_TASK', payload: { id: 1, text: 'Task', completed: false } }); javascript // ✅ Correct import { addTask } from './actions'; dispatch(addTask({ id: 1, text: 'Task', completed: false }));Erreur :
Uncaught Error: Unexpected value of type "undefined" for key "_reactReduxContext". Make sure to follow the instructions in the React Redux docs for passing the store.// ❌ Mauvais ReactDOM.render(<App />, document.getElementById('root')); javascript // ✅ Correct import { Provider } from 'react-redux'; import store from './store'; ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') );
Pour aller plus loin
- Utiliser les Selectors : Pour séparer la logique de sélection d'état du reste de votre application.
- Asynchronous Actions with Redux-Thunk : Pour gérer des actions asynchrones comme des appels API.
- Redux DevTools : Pour inspecter l'état de votre application et voir les modifications à chaque dispatch.
Défi pratique : Créez une application simple de gestion de notes avec la possibilité d'ajouter, modifier et supprimer des notes. Utilisez Redux pour gérer le state global des notes.