Zustand vs Redux Toolkit vs Jotai en React Native : Le Guide de la Gestion d'État (2026)
Zustand, Redux Toolkit ou Jotai en React Native 2026 ? Comparaison bundle, performance, DevTools et code TypeScript pour choisir la bonne bibliothèque de gestion d'état selon votre équipe.
En React Native en 2026, Zustand est devenu le choix par défaut pour l'état client global grâce à ses 1,1 Ko de bundle et son API sans boilerplate, tandis que Redux Toolkit reste le standard des équipes de plus de cinq personnes qui ont besoin de RTK Query et du time-travel debugging, et Jotai s'impose dès que votre état ressemble à un graphe de valeurs dérivées. Venant du web, j'ai vécu la même migration Redux → Zustand deux fois : côté React DOM puis côté React Native. Les conclusions se ressemblent, mais les contraintes mobiles (cold start, Hermes, JSI) changent certains arbitrages. Ce guide compare les trois bibliothèques avec des benchmarks 2026, du code TypeScript exécutable et une grille de décision honnête.
Zustand pèse 1,1 Ko contre 3,5 Ko pour Jotai et 11,1 Ko pour Redux Toolkit, un écart qui compte sur cold start Hermes.
Zustand est passé de 26,7 M à 72,9 M de téléchargements mensuels entre 2024 et 2026 ; Redux a chuté de 57 % à 38 % de parts de marché en React Native.
Redux Toolkit reste préférable pour les équipes de 5+ développeurs grâce à RTK Query, Redux DevTools et une architecture imposée.
Jotai gagne sur l'état atomique et les valeurs dérivées : parfait pour des formulaires complexes ou des UI très granulaires.
Le pattern gagnant en 2026 : TanStack Query pour l'état serveur + Zustand ou Jotai pour l'état client, jamais les deux dans le même slice.
La persistance sur mobile passe par MMKV (via zustand/middleware ou redux-persist), pas AsyncStorage pour les stores volumineux.
Panorama de l'état en React Native en 2026
La question « quelle bibliothèque de gestion d'état choisir en React Native » ne se pose plus dans les mêmes termes qu'en 2022. À l'époque, Redux dominait à 57 % dans les enquêtes React Native, MobX résistait dans les grosses bases, et Context API servait de rustine pour tout le monde. En 2026, la répartition est très différente : Zustand a triplé son adoption pour atteindre environ 41 millions de téléchargements hebdomadaires npm, Redux Toolkit s'est modernisé mais recule à 38 % de parts de marché mobile, et Jotai s'est stabilisé sur une niche « atomique » avec un lectorat fidèle.
Ce qui a changé structurellement, c'est que la communauté a arrêté de mélanger état serveur et état client dans le même store. TanStack Query (ex-React Query) absorbe désormais tout ce qui est fetch, cache, invalidation et retry, ce qui vide considérablement les stores globaux. Résultat : un store Zustand typique de 2026 contient l'auth, les préférences UI, la file d'attente offline et deux ou trois flags. Ça ne justifie plus 11 Ko de boilerplate Redux.
Venant de React Web, la bascule est fluide : Zustand, Redux Toolkit et Jotai fonctionnent exactement pareil sur les deux plateformes. Les seules différences côté React Native sont le stockage persistant (MMKV plutôt que localStorage), le cold start (chaque kilo-octet compte sur Hermes), et l'absence de Redux DevTools natives sans passer par React Native DevTools ou Flipper. Pour un retour d'expérience sur l'outillage moderne, voyez notre guide React Native DevTools.
Zustand : le nouveau standard par défaut
Zustand (« état » en allemand) est une bibliothèque de 1,1 Ko qui expose un seul concept : un hook. Vous créez un store avec create(), vous le consommez avec un sélecteur. Pas de Provider, pas d'actions, pas de reducers séparés. Pour quelqu'un qui vient de useState côté web, c'est la transition la plus douce du marché : votre code ressemble à un hook maison qui aurait une portée globale.
Voici un store d'authentification typique en TypeScript, tel que je l'écris dans mes projets Expo actuels :
Dans un composant, on consomme uniquement la tranche nécessaire, ce qui évite les re-renders inutiles :
// screens/ProfileScreen.tsx
import { useAuthStore } from '../stores/authStore'
export function ProfileScreen() {
const user = useAuthStore((s) => s.user)
const signOut = useAuthStore((s) => s.signOut)
if (!user) return null
return <Button title={`Déconnecter ${user.email}`} onPress={signOut} />
}
Ce que j'apprécie côté mobile : le middleware persist se branche sur MMKV en cinq lignes, et le pattern onRehydrateStorage permet de bloquer l'écran de démarrage tant que le store n'est pas prêt (indispensable pour éviter les flashes d'écran d'auth). La documentation officielle Zustand couvre les patterns Immer, subscribe et transient updates si vous voulez pousser plus loin.
Redux Toolkit : le poids lourd de l'entreprise
Redux Toolkit (RTK) n'est plus le Redux verbeux de 2018. En 2026, un slice RTK moderne fait 30 lignes, gère l'immutabilité via Immer sous le capot, et intègre RTK Query pour l'état serveur. Pour les équipes de 5+ développeurs, c'est encore le choix rationnel : les patterns sont imposés, le time-travel debugging via Redux DevTools reste sans équivalent, et RTK Query évite d'installer TanStack Query séparément.
Voici un slice d'authentification équivalent à l'exemple Zustand, avec un endpoint RTK Query :
La force ici, c'est que useMeQuery vous donne data, isLoading, error, cache, refetch automatique et invalidation par tag, le tout intégré au même store Redux. Si vous choisissez Zustand, vous devez installer TanStack Query en plus (ce qui reste très raisonnable). Consultez les notes RTK Query officielles pour la configuration complète cache-and-network.
Honnêtement, le vrai coût de Redux Toolkit sur mobile n'est pas les 11 Ko de bundle. C'est la charge cognitive pour les nouveaux arrivants. J'ai onboardé une équipe de trois juniors sur un projet RTK l'année dernière : deux semaines avant qu'ils comprennent le flux slice → dispatch → selector → re-render. Sur un projet Zustand équivalent, une journée pleine. À vous de calculer si le time-travel vaut cette différence.
Jotai : l'approche atomique
Jotai renverse le modèle : au lieu d'un store unique, vous déclarez des atomes, c'est-à-dire des unités d'état minuscules et composables. Chaque atome peut être primitif ou dérivé, et les composants s'abonnent uniquement aux atomes qu'ils consomment. C'est très proche de l'API useState, mais partageable entre composants sans Provider global obligatoire.
// components/CartBadge.tsx
import { useAtomValue } from 'jotai'
import { cartCountAtom } from '../atoms/cartAtoms'
export function CartBadge() {
const count = useAtomValue(cartCountAtom)
return <Text>{count}</Text>
}
La granularité est le point fort : CartBadge ne se rend que si cartCountAtom change réellement. Si vous modifiez la quantité d'un article sans changer le nombre d'articles, le badge ne bouge pas. En Zustand ou Redux, il faut être discipliné avec les sélecteurs mémoïsés pour obtenir le même comportement.
Jotai brille dans deux scénarios : les formulaires complexes avec beaucoup de champs dépendants, et les UI de type dashboard où chaque tuile calcule sa propre valeur dérivée d'un état partagé. En revanche, la persistance et le time-travel restent plus rustiques qu'avec Redux Toolkit. Pour un aperçu complet, la documentation officielle Jotai est excellente.
Tableau comparatif détaillé
Voici les dimensions qui comptent réellement quand vous choisissez pour un projet React Native en 2026. Chiffres tirés des benchmarks 2026 (M1 MacBook Pro, React 19, Hermes, 1 000 composants abonnés) et de mes mesures internes sur Expo SDK 55.
Critère
Zustand
Redux Toolkit
Jotai
Taille bundle (min+gzip)
1,1 Ko
11,1 Ko
3,5 Ko
Boilerplate
Minimal
Modéré
Minimal
Temps de rendu (1 update / 1000 composants)
12 ms
18 ms
14 ms
Mémoire (1000 abonnements)
2,1 Mo
3,2 Mo
1,8 Mo
État serveur
+ TanStack Query
RTK Query intégré
+ TanStack Query
DevTools
Basique
Redux DevTools (time-travel)
Extension Chrome
Courbe d'apprentissage
Douce
Modérée
Douce
Idéal pour
Petites/moyennes équipes
Grandes équipes, apps critiques
Formulaires, UI granulaires
Téléchargements mensuels (2026)
~72,9 M
~37,1 M
~14 M
Comment choisir entre Zustand, Redux et Jotai ?
La question posée le plus souvent en entretien technique est aussi la plus mal posée : il n'existe pas de « meilleure » bibliothèque, il existe des combinaisons projet + équipe pour lesquelles chacune est optimale. Voici la grille de décision que j'utilise en consulting.
Choisissez Zustand si :
Votre équipe fait moins de 5 développeurs React Native.
Vous démarrez un projet en 2026 sans historique Redux.
Le cold start et la taille du bundle sont critiques (apps grand public).
Vous utilisez déjà TanStack Query pour l'API.
Vous voulez tester rapidement des idées sans architecture rigide.
Choisissez Redux Toolkit si :
Votre équipe compte 5+ développeurs qui ont besoin de patterns imposés.
Vous voulez RTK Query intégré sans installer TanStack Query.
Le time-travel debugging via Redux DevTools est important (apps de trading, de santé, workflows critiques).
Votre codebase existante est déjà en Redux et migrer n'apporte pas de valeur métier.
Vous devez auditer chaque changement d'état (logs, replay, forensics).
Choisissez Jotai si :
Votre UI est très granulaire avec beaucoup de valeurs dérivées.
Vous construisez des formulaires complexes (Jotai + Zod est une combinaison redoutable).
Vous voulez éviter les re-renders inutiles sans écrire de sélecteurs mémoïsés.
La règle d'or de 2026 : ne mettez jamais de données serveur dans Zustand ou Jotai. TanStack Query gère mieux le cache, la déduplication, le refetch en arrière-plan, les retries exponentiels et la pagination. Redux Toolkit propose l'équivalent via RTK Query, ce qui simplifie l'arbitrage.
// hooks/useUserProjects.ts
import { useQuery } from '@tanstack/react-query'
import { useAuthStore } from '../stores/authStore'
export function useUserProjects() {
const token = useAuthStore((s) => s.token)
return useQuery({
queryKey: ['projects', 'me'],
queryFn: async () => {
const res = await fetch('https://api.example.com/projects', {
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok) throw new Error('Failed to fetch projects')
return res.json() as Promise<Project[]>
},
enabled: !!token,
staleTime: 60 * 1000,
})
}
Zustand contient le token (état client), TanStack Query contient les projets (état serveur). Aucune donnée n'est dupliquée, et le hook useUserProjects se met à jour tout seul quand l'utilisateur se reconnecte. C'est aussi le pattern qui rend l'offline-first tractable : TanStack Query gère la file de mutations, Zustand marque l'état « offline » pour l'UI. Pour aller plus loin sur le débogage réseau, notre guide React Native DevTools détaille l'inspection réseau.
Persistance et hydratation avec MMKV
AsyncStorage tourne sur un thread séparé et sérialise en JSON, ce qui devient lent dès que vous dépassez quelques kilo-octets. En 2026, react-native-mmkv est le stockage clé-valeur par défaut sur mobile : synchrone, 30 fois plus rapide, et compatible avec la New Architecture. Les trois bibliothèques s'y branchent proprement.
Point important côté migration depuis le web : localStorage n'existe pas, mais MMKV a une API très similaire. Le piège classique est de vouloir tout persister. N'incluez que ce qui doit survivre à un cold start (auth, préférences, file offline), pas le contenu des listes ou les données serveur. Ces dernières appartiennent à TanStack Query, qui a son propre cache persistant via @tanstack/query-async-storage-persister.
Réduire les re-renders avec useShallow et selectAtom
Le pire piège en gestion d'état sur mobile n'est pas la taille du bundle : c'est la cascade de re-renders qui plombe les listes longues et les animations Reanimated. Chaque bibliothèque expose un mécanisme pour l'éviter, et c'est ce qui différencie une app fluide d'une app saccadée sur un mid-range Android.
Avec Zustand, useShallow compare les objets renvoyés par un sélecteur superficiellement :
import { useShallow } from 'zustand/react/shallow'
// Sans useShallow : re-render à chaque mise à jour de n'importe quelle clé
const { user, token } = useAuthStore((s) => ({ user: s.user, token: s.token }))
// Avec useShallow : re-render uniquement si user OU token change réellement
const { user, token } = useAuthStore(useShallow((s) => ({ user: s.user, token: s.token })))
Avec Jotai, selectAtom et focusAtom jouent le même rôle, mais c'est natif : chaque atome est déjà une unité de re-render. Avec Redux Toolkit, utilisez createSelector (Reselect) pour mémoïser les sélecteurs coûteux. Combiné avec une FlashList v2, on peut afficher 10 000 éléments avec des mises à jour d'état sans dropped frames. Voir notre comparaison FlatList vs FlashList v2 pour les mesures.
Un dernier conseil de terrain : profitez du menu Perf Monitor de React Native DevTools pour tracer les re-renders excessifs. C'est en général là qu'on découvre qu'on a oublié un useShallow ou qu'un composant lit tout le store au lieu d'une tranche. La leçon vaut pour les trois bibliothèques.
Questions fréquentes
Zustand est-il vraiment plus rapide que Redux Toolkit en React Native ?
Oui, dans les benchmarks 2026, Zustand rend en 12 ms contre 18 ms pour Redux Toolkit sur 1 000 composants abonnés. La différence vient surtout du bundle (1,1 Ko vs 11,1 Ko) qui pèse au cold start Hermes. Pour une app moyenne avec quelques centaines d'abonnés, la différence de rendu est imperceptible.
Peut-on utiliser Zustand et Redux Toolkit dans le même projet ?
Techniquement oui, mais c'est rarement une bonne idée sauf en phase de migration. Le coût cognitif d'apprendre deux modèles mentaux pour l'équipe dépasse en général les bénéfices. Préférez migrer feature par feature vers une seule bibliothèque, ou combinez avec Jotai qui a un rôle très distinct (état atomique / formulaires).
Jotai remplace-t-il Zustand ou est-ce complémentaire ?
C'est complémentaire. Jotai excelle sur l'état atomique et les valeurs dérivées (formulaires, dashboards), tandis que Zustand est meilleur pour un store global classique (auth, préférences, feature flags). Beaucoup d'apps 2026 utilisent Zustand pour le global et Jotai pour les formulaires complexes, sans conflit.
Faut-il abandonner Context API en React Native en 2026 ?
Non, mais restreignez-le aux valeurs à faible fréquence de mise à jour : session authentifiée, thème, langue, injection de dépendances. Pour tout état qui change souvent (compteurs, listes, formulaires), Context déclenche trop de re-renders et vous devriez basculer sur Zustand ou Jotai.
Zustand fonctionne-t-il avec la New Architecture (Fabric, TurboModules) ?
Oui, Zustand est du JavaScript pur et ne dépend d'aucun module natif, donc il est compatible sans configuration avec Fabric et TurboModules. Le seul point d'attention concerne le middleware persist avec MMKV : assurez-vous d'utiliser la version 3.x de react-native-mmkv, qui supporte pleinement la New Architecture.
Comment migrer un projet Redux vers Zustand progressivement ?
Créez d'abord vos nouveaux stores Zustand en parallèle du store Redux existant. Migrez feature par feature : commencez par les slices les plus indépendants (UI, préférences), gardez Redux pour les workflows critiques et RTK Query. Une migration complète prend en général 4 à 8 semaines pour une base moyenne, avec zéro downtime si vous avancez slice par slice.