# Chapitre 3 : Redux et Redux Toolkit
## Pourquoi Redux ?
Context est bien pour des données simples (thème, utilisateur). Mais pour des applications complexes :
- État partagé entre beaucoup de composants
- Logique de mise à jour complexe
- Besoin d'un historique des actions (debug)
- Performance avec de nombreuses mises à jour
Redux offre une solution structurée et prévisible.
## Les concepts fondamentaux
### 1. Store
Le **store** est l'unique source de vérité. Tout l'état de l'application est dans un seul objet.
```javascript
{
user: { id: 1, name: 'Jean' },
products: [...],
cart: { items: [], total: 0 },
ui: { isLoading: false, error: null }
}
```
### 2. Actions
Les **actions** décrivent ce qui s'est passé. Ce sont des objets avec un `type` :
```javascript
{ type: 'cart/addItem', payload: { id: 1, name: 'Produit', price: 29.99 } }
{ type: 'user/login', payload: { id: 1, name: 'Jean' } }
{ type: 'ui/setLoading', payload: true }
```
### 3. Reducers
Les **reducers** spécifient comment l'état change en réponse à une action :
```javascript
function cartReducer(state, action) {
switch (action.type) {
case 'cart/addItem':
return {
...state,
items: [...state.items, action.payload]
};
case 'cart/removeItem':
return {
...state,
items: state.items.filter(item => item.id !== action.payload)
};
default:
return state;
}
}
```
### Le flux Redux
```
Action → Reducer → Nouveau State → UI mise à jour
```
1. Un événement déclenche une action
2. Le reducer calcule le nouvel état
3. Le store notifie les composants
4. Les composants se re-rendent
## Redux Toolkit : Redux simplifié
Redux classique nécessite beaucoup de code. **Redux Toolkit** (RTK) simplifie tout :
```bash
npm install @reduxjs/toolkit react-redux
```
## Créer un Slice
Un **slice** regroupe l'état, les reducers et les actions pour une fonctionnalité :
```javascript
// features/counter/counterSlice.js
import { createSlice } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0
},
reducers: {
increment: (state) => {
// RTK utilise Immer : on peut "muter" directement
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
incrementByAmount: (state, action) => {
state.value += action.payload;
}
}
});
// Export des actions
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
// Export du reducer
export default counterSlice.reducer;
```
## Configurer le Store
```javascript
// app/store.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from '../features/counter/counterSlice';
export const store = configureStore({
reducer: {
counter: counterReducer
}
});
```
## Connecter React au Store
```javascript
// index.js ou App.js
import { Provider } from 'react-redux';
import { store } from './app/store';
function App() {
return (
);
}
```
## Utiliser Redux dans un composant
```javascript
// features/counter/Counter.js
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement, incrementByAmount } from './counterSlice';
function Counter() {
// Lire l'état
const count = useSelector(state => state.counter.value);
// Obtenir la fonction dispatch
const dispatch = useDispatch();
return (