State Management Moderne en 2025 : Pourquoi Zustand et Jotai Surpassent Redux
Salut HaWkers, pendant des années Redux a été le standard pour la gestion d'état dans React. Mais en 2025, les développeurs abandonnent Redux en masse pour des solutions plus simples et modernes.
Zustand et Jotai représentent une nouvelle génération de state management : moins de boilerplate, meilleure performance, et developer experience supérieure.
Le Problème avec Redux
// Redux - Beaucoup de boilerplate pour quelque chose de simple
// actions/counter.js
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
export const increment = () => ({ type: INCREMENT });
export const decrement = () => ({ type: DECREMENT });
// reducers/counter.js
const initialState = { count: 0 };
export default function counterReducer(state = initialState, action) {
switch (action.type) {
case INCREMENT:
return { ...state, count: state.count + 1 };
case DECREMENT:
return { ...state, count: state.count - 1 };
default:
return state;
}
}
// store.js
import { createStore, combineReducers } from 'redux';
import counterReducer from './reducers/counter';
const rootReducer = combineReducers({
counter: counterReducer
});
export const store = createStore(rootReducer);
// Component.jsx
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from './actions/counter';
function Counter() {
const count = useSelector(state => state.counter.count);
const dispatch = useDispatch();
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch(increment())}>+</button>
<button onClick={() => dispatch(decrement())}>-</button>
</div>
);
}
// 6 fichiers, ~60 lignes pour un compteur ! 😱
Zustand : Simplicité Extrême
// store/counter.js - TOUT le state management dans un fichier !
import { create } from 'zustand';
export const useCounterStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 })
}));
// Component.jsx
import { useCounterStore } from './store/counter';
function Counter() {
const { count, increment, decrement } = useCounterStore();
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
);
}
// 2 fichiers, ~20 lignes. Beaucoup plus simple ! ✨Zustand Features Avancées
// store/user.js - Store complète avec middleware
import { create } from 'zustand';
import { persist, devtools } from 'zustand/middleware';
export const useUserStore = create(
devtools(
persist(
(set, get) => ({
user: null,
token: null,
isAuthenticated: false,
// Actions
login: async (email, password) => {
const response = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify({ email, password })
});
const { user, token } = await response.json();
set({
user,
token,
isAuthenticated: true
});
},
logout: () => set({
user: null,
token: null,
isAuthenticated: false
}),
updateProfile: (updates) => set((state) => ({
user: { ...state.user, ...updates }
})),
// Selectors calculés
get fullName() {
const { user } = get();
return user ? `${user.firstName} ${user.lastName}` : '';
}
}),
{
name: 'user-storage', // Clé LocalStorage
partialize: (state) => ({
token: state.token,
user: state.user
})
}
)
)
);
Jotai : Atomic State Management
// atoms/counter.js
import { atom } from 'jotai';
// Atoms primitifs
export const countAtom = atom(0);
// Derived atoms (calculés)
export const doubledCountAtom = atom((get) => get(countAtom) * 2);
// Write-only atom (actions)
export const incrementAtom = atom(
null,
(get, set) => set(countAtom, get(countAtom) + 1)
);
export const decrementAtom = atom(
null,
(get, set) => set(countAtom, get(countAtom) - 1)
);
// Component.jsx
import { useAtom, useAtomValue, useSetAtom } from 'jotai';
import { countAtom, doubledCountAtom, incrementAtom } from './atoms/counter';
function Counter() {
const count = useAtomValue(countAtom);
const doubled = useAtomValue(doubledCountAtom);
const increment = useSetAtom(incrementAtom);
return (
<div>
<p>Count: {count}</p>
<p>Doubled: {doubled}</p>
<button onClick={increment}>+</button>
</div>
);
}Jotai avec Async Data
// atoms/users.js
import { atom } from 'jotai';
// Async atom - cherche les données automatiquement
export const usersAtom = atom(async () => {
const response = await fetch('/api/users');
return response.json();
});
// Atom avec refresh
export const refreshUsersAtom = atom(null, async (get, set) => {
const users = await fetch('/api/users').then(r => r.json());
set(usersAtom, users);
});
// Filtered atom
export const activeUsersAtom = atom((get) => {
const users = get(usersAtom);
return users.filter(user => user.active);
});
// Component.jsx - Suspense out-of-the-box !
import { Suspense } from 'react';
import { useAtomValue } from 'jotai';
import { usersAtom, activeUsersAtom } from './atoms/users';
function UserList() {
const activeUsers = useAtomValue(activeUsersAtom);
return (
<ul>
{activeUsers.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
// App.jsx
function App() {
return (
<Suspense fallback={<div>Chargement des utilisateurs...</div>}>
<UserList />
</Suspense>
);
}
Comparaison : Redux vs Zustand vs Jotai
| Feature | Redux | Zustand | Jotai |
|---|---|---|---|
| Bundle Size | ~40 KB | ~1.2 KB | ~2.8 KB |
| Boilerplate | Élevé | Bas | Moyen |
| Learning Curve | Abrupte | Douce | Moyenne |
| Performance | Bonne | Excellente | Excellente |
| DevTools | Oui | Oui | Oui |
| Persistence | Middleware | Built-in | Extensions |
| TypeScript | Complexe | Simple | Excellent |
| Async | Thunks/Saga | Natif | Natif |
Quand Utiliser Chacun
Utilisez Zustand quand :
✅ Vous voulez la simplicité maximale
✅ State global simple à modéré
✅ Vous avez besoin de persistence facile
✅ Vous venez du Context API
✅ Équipe petite/moyenne
Utilisez Jotai quand :
✅ Vous préférez l'atomic state
✅ Vous avez besoin de derived state complexe
✅ Suspense et async sont importants
✅ Fine-grained reactivity
✅ Influence de Recoil/atoms
Utilisez Redux quand :
✅ Projet enterprise grand
✅ Time-travel debugging essentiel
✅ Écosystème Redux nécessaire
✅ Équipe maîtrise déjà Redux
✅ State extrêmement complexe
Migrer de Redux
// Avant : Redux
const mapStateToProps = (state) => ({
count: state.counter.count,
user: state.user.data
});
const mapDispatchToProps = {
increment,
fetchUser
};
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);
// Après : Zustand
import { useCounterStore } from './store/counter';
import { useUserStore } from './store/user';
function MyComponent() {
const count = useCounterStore(state => state.count);
const increment = useCounterStore(state => state.increment);
const user = useUserStore(state => state.user);
const fetchUser = useUserStore(state => state.fetchUser);
// Beaucoup plus simple et direct !
}Si vous voulez mieux comprendre les tendances modernes de React, consultez : Svelte 5 Runes : La Révolution de Réactivité où nous explorons comment les frameworks modernes réimaginent le state management.
C'est parti ! 🦅
💻 Maîtrisez JavaScript Pour de Vrai
Le savoir que vous avez acquis dans cet article n'est que le début. Il y a des techniques, patterns et pratiques qui transforment les développeurs débutants en professionnels recherchés.
Formes de paiement :
- €9,90 (paiement unique)

