import { create } from 'zustand';
interface DashboardState {
filter: string;
theme: 'light' | 'dark';
setFilter: (val: string) => void;
}
// Store-ul global nu are nevoie de Provider în React 18
export const useDashboardStore = create<DashboardState>((set) => ({
filter: '',
theme: 'dark',
setFilter: (val) => set({ filter: val }),
}));
// În componentă importi DOAR ce ai nevoie
// Componenta se va re-rendera doar când se schimbă exact această valoare
const FilterComponent = () => {
const filter = useDashboardStore((state) => state.filter);
const setFilter = useDashboardStore((state) => state.setFilter);
return <input value={filter} onChange={(e) => setFilter(e.target.value)} />;
};Salutare! Văd des discuția asta pe forumuri și în echipe: „Nu mai punem Redux, facem cu useReducer și Context”. Sună bine pe hârtie, dar în practică de multe ori ne complicăm viața singuri fără un motiv real. Hai să vedem unde e granița dintre ele și cum să nu-ți blochezi aplicația în re-renderări inutile.
Cazul meu: cum am înecat un dashboard în Context
La un proiect trecut, am avut de făcut un dashboard cu vreo 18 widget-uri interactive. Fiecare widget trebuia să știe ce face celălalt, să trimită filtre, să schimbe scheme de culori și tot așa. Am zis să fim „băieți deștepți” și să nu aducem biblioteci externe. Am trântit un useReducer legat de un React.Context la rădăcină.
Ce s-a întâmplat? Când userul schimba un singur filtru dintr-un dropdown mic, toată pagina îngheța pentru 200ms. De ce? Pentru că orice update în Context-ul ăla redistribuia starea către toate cele 18 widget-uri, forțând re-render pe componente care nici măcar nu aveau treabă cu filtrul respectiv. Am pierdut două zile optimizând cu useMemo și React.memo până când mi-am dat seama că luptam cu tool-ul, nu cu problema.
Unde strălucește useReducer cu adevărat?
Nu mă înțelegeți greșit, useReducer este genial. Dar locul lui este local, în interiorul unei singure componente complexe sau a unui arbore foarte strâns de componente.
Dacă ai un formular gigant de onboarding cu 4 pași, validări interdependente și 20 de câmpuri, useReducer e sfânt. Îți ține logica de tranziție a stării curată, într-un singur loc (reducerul), ferită de restul aplicației.
Trade-off-ul sincer: e super pentru modularitate și testat logica pură (fără React), dar e groaznic când vrei să împarți starea aia cu o componentă din cealaltă parte a ecranului. Când începi să pasezi dispatch-ul prin 3 niveluri de props sau să creezi contexte separate pentru stare și dispatch doar ca să eviți re-renderările, e clar că ai trecut de limita de utilitate.
Zustand: simplitatea de care avem nevoie în producție
După eșecul cu dashboard-ul ăla, am rescris tot state management-ul în Zustand într-o după-amiază. Am șters cam 30% din codul de boilerplate pentru că am scăpat de Providers și de acțiunile repetitive.
Zustand rezolvă fix problema re-renderărilor prin selecție atomică. Componenta X ascultă doar la state.filter, componenta Y doar la state.theme. Dacă se schimbă filtrul, componenta Y nici nu clipește. În plus, codul e incredibil de curat și poți modifica starea direct din afara componentelor React dacă ai nevoie (de exemplu, într-un interceptor de Axios pentru a curăța token-ul la logout).
Cum alegi rapid?
Regula mea de deget (rule of thumb) e simplă:
- Ai nevoie de starea aia în mai mult de două pagini sau în componente care nu au o relație directă de rudenie? Zustand (sau alt store extern).
- Ai o singură componentă super complexă, cu multe acțiuni interne care depind una de alta? useReducer local, fără Context.
Voi cum gestionați starea globală acum? Mai folosește cineva Redux ToolKit sau ați trecut toți pe Zustand și Jotai?