Aller au contenu

ADR-003 — Gestion d'état à trois niveaux (Redux + Zustand + Context)

Statut

Accepté

Date

2026-07-08 (documenté rétroactivement)

Contexte

L'application a de l'état à des portées très différentes : données de session persistées globalement (token d'auth, utilisateur, files offline, langue, thème), état UI/domaine local à une feature, et état partagé à portée réduite (l'appareil BLE connecté, les dialogs). Faire passer tout cela par un unique store global crée du boilerplate et du couplage ; l'éparpiller au cas par cas crée de l'incohérence.

Décision

Utiliser trois niveaux, chacun pour une portée distincte :

  1. Redux (global, persisté)src/store/. Redux Toolkit configure le store ; les reducers sont des ducks écrits à la main (constante d'action + creator + switch + selectors par fichier), persistés via redux-persist. Pour l'état à l'échelle de l'app, inter-écrans ou persisté : token, user, online, trackedQueries, syncManager, measures, language, themeMode, …
  2. Zustand (local à une feature) — un store léger à l'intérieur d'une feature (ex. unitPreference/hooks/unitPreference.store.ts) pour l'état possédé par une seule feature.
  3. React Context (portée réduite) — pour une préoccupation partagée dans un sous-arbre : appareil BLE et dialogs (src/utils/context/), et contextes de feature (changeMode/context/).

Ligne directrice : persisté/global → duck Redux ; possédé par une feature → zustand ; partagé dans un sous-arbre/éphémère → context. N'ajoutez pas de duck global pour de l'état local à une feature.

Conséquences

Positives

  • Chaque portée utilise l'outil le plus léger qui convient ; moins de boilerplate pour l'état local à une feature.
  • Les nouvelles features peuvent gérer leur propre état sans toucher au store global.
  • La whitelist persistée reste petite et intentionnelle.

Négatives / Compromis

  • Trois bibliothèques d'état à apprendre.
  • La frontière est une ligne directrice, non imposée — risque de dérive (quelque chose de local à une feature qui fuit dans Redux).
  • Les ducks sont le style legacy (switch manuel), pas createSlice, alors que RTK est disponible — incohérent avec les conventions RTK modernes.

Alternatives considérées

  • Redux partout — rejeté : trop de boilerplate pour l'état local à une feature, et couple les features au store global.
  • Migrer tous les ducks vers createSlice de RTK — reporté : gros changement mécanique à faible bénéfice immédiat ; les nouvelles features utilisent simplement zustand.
  • Uniquement Zustand/Context (abandonner Redux) — rejeté : redux-persist + les ducks de file offline sont porteurs et éprouvés.