import { create } from 'zustand';
interface DashboardState {
metrics: Record<string, number>;
updateMetric: (key: string, value: number) => void;
}
// Store global curat, fără provideri sau context hell
export const useDashboardStore = create<DashboardState>((set) => ({
metrics: {},
updateMetric: (key, value) =>
set((state) => ({
metrics: { ...state.metrics, [key]: value }
})),
}));
// Componenta se rerandează DOAR când se schimbă metrica 'revenue'
export function RevenueWidget() {
const revenue = useDashboardStore((state) => state.metrics['revenue'] ?? 0);
return <div className="card">Revenue: {revenue} EUR</div>;
}Am văzut mulți devi care se bat în piept că useReducer plus React Context reprezintă soluția perfectă pentru orice aplicație, în timp ce alții bagă Zustand direct din npm init. După zece ani de React și zeci de refactoring-uri dureroase, mi-am dat seama că ambele tabere greșesc când generalizează. Hai să vedem exact unde tragem linia între ele, pe cifre și pe cazuri reale din producție.
Când te salvează useReducer (și când devine iad)
La un proiect mai vechi, un configurator complex de produse cu vreo 80 de opțiuni interdependente, am mers pe useReducer. De ce? Pentru că logica de business era strâns legată de UI-ul local. Când bifezi opțiunea A, trebuie să validezi B, să resetezi C și să recalculezi prețul final. Un reducer pur, local, e perfect aici. Îl testezi extrem de ușor în Jest cu intrări și ieșiri clare, fără să-ți pese de mediul React.
Dar problemele apar când vrei să muți starea asta mai sus. Am făcut greșeala să ridicăm acel reducer într-un Context pentru a-l share-ui cu alte componente din pagină. Rezultatul? Un dezastru de performanță. La fiecare apăsare de tastă, tot arborele de componente se reredera deoarece Context-ul nu are selectoare native. Am încercat să optimizăm cu useMemo și să spargem contextul în trei, dar codul a devenit rapid de necitit și greu de întreținut.
Zustand: de ce a câștigat războiul stării globale
Aici intervine Zustand. La un alt proiect, un dashboard financiar cu peste 10k de metrici actualizate în timp real prin WebSocket-uri, am trecut direct pe Zustand. Am economisit cam 30% la timpul de dezvoltare doar pentru că am scăpat de boilerplate-ul de provideri.
Zustand funcționează în afara arborelui React. Componentele se abonează doar la feliile de stare de care au nevoie prin selectoare. Dacă se schimbă doar user.name, componenta care afișează soldul din cont nu se va reredera. E simplu, rapid și extrem de curat. În plus, poți schimba starea direct din acțiuni asincrone fără să ai nevoie de middleware-uri dubioase sau thunk-uri complicate.
Trade-off-ul sincer pe care nu-l vezi în tutoriale
Sună prea frumos ca să fie adevărat? Iată buba. Cu Zustand e extrem de ușor să scrii cod de tip "spaghete". Deoarece poți modifica starea de oriunde, riști să ajungi la situații în care nu mai știi ce acțiune a declanșat o schimbare bizară în UI.
La useReducer, fluxul e unidirecțional și rigid, ceea ce te obligă să fii disciplinat. În Zustand, dacă nu ești atent și începi să modifici store-ul direct din componente în loc să folosești acțiuni bine definite în interiorul store-ului, ai pierdut controlul asupra debug-ului.
Regula mea de aur e simplă: dacă starea aparține unei singure pagini sau unui singur formular complex, useReducer local câștigă detașat. Dacă starea trebuie partajată între rute sau componente îndepărtate în arbore, aruncă Context-ul la gunoi și folosește Zustand cu încredere.
Voi cum gestionați starea globală în proiectele medii? Tot Redux Toolkit a rămas standardul la voi în firmă sau ați trecut pe ceva mai light?