import { create } from 'zustand';
interface CartState {
items: string[];
addItem: (item: string) => void;
clearCart: () => void;
}
export const useCartStore = create<CartState>((set) => ({
items: [],
addItem: (item) => set((state) => ({
items: [...state.items, item]
})),
clearCart: () => set({ items: [] }),
}));
// Utilizare într-o componentă
const CartCount = () => {
const count = useCartStore((state) => state.items.length);
return <span>Produse: {count}</span>;
};Acum vreo trei luni, lucram la un sistem de checkout pentru un client din zona de e-commerce. Inițial, am zis că suntem băieți deștepți și că rezolvăm totul cu useState și câteva callback-uri pasate prin props. După două săptămâni, aveam un prop-drilling de toată frumusețea, unde o componentă de tip SummaryCard primea date prin cinci intermediari care nici măcar nu știau ce-s alea. Atunci apare întrebarea clasică pe care o văd zilnic pe forumuri: ce folosim când lucrurile devin complicate?
Puterea subestimată a lui useReducer
useReducer este, din punctul meu de vedere, una dintre cele mai puțin înțelese unelte din arsenalul de bază al React-ului. Mulți fug de el pentru că le aduce aminte de Redux, de acele switch-case-uri interminabile și de cerința de a scrie dispatch({ type: '...' }). Dar adevărul e că pentru logica locală complexă, useReducer e imbatabil.
Dacă ai un formular cu 15 câmpuri unde validarea unuia depinde de starea altuia, sau un tabel cu filtrare, sortare și paginare, un useReducer bine structurat îți curăță componenta de logică imperativă. Totuși, marea greșeală pe care o văd la developeri este încercarea de a simula un store global combinând useReducer cu Context API. Da, funcționează, dar performanța are de suferit. Orice schimbare în context va declanșa re-randări în toate componentele consumatoare, dacă nu ești extrem de atent cu memoizarea (React.memo, useMemo). Pe proiectul X, am pierdut două zile optimizând un context care creștea ca un monstru, când soluția era mult mai simplă.
Zustand: Simplitatea care te salvează
Aici intervine Zustand. Dacă Redux era tăticul care te punea să completezi trei formulare înainte să primești o bomboană, Zustand e unchiul cool care îți dă cheile de la mașină fără să pună întrebări. Ce îmi place la el este simplitatea absolută. Creezi un store, definești acțiunile direct în el și gata.
Nu ai nevoie de un Provider care să îmbrace toată aplicația, ceea ce înseamnă că poți accesa starea chiar și în afara componentelor React. De exemplu, poți citi un token de autentificare dintr-un store Zustand direct într-un interceptor de Axios sau într-un utilitar de logging, fără să te chinui cu hook-uri în funcții care nu sunt componente. Pe lângă asta, sistemul de selectări (selectors) din Zustand este nativ și extrem de eficient: componenta se randează doar dacă valoarea specifică pe care o asculți s-a schimbat.
Trade-off-uri și decizia finală
Când facem alegerea? Eu merg pe o regulă simplă: dacă starea este privată pentru un anumit workflow (de exemplu, pașii dintr-un wizard care nu mai sunt relevanți după ce ai închis modalul), folosesc useReducer. E curat, e standard și nu adaugă dependențe externe în bundle.
În schimb, dacă datele trebuie să fie accesibile cross-feature (datele userului, setările de temă, coșul de cumpărături), Zustand e alegerea logică. În proiectul de e-commerce menționat, am făcut greșeala să ținem coșul într-un context cu useReducer. Când am ajuns la 50 de produse, fiecare 'add to cart' îngheța UI-ul pentru 200ms din cauza re-randărilor masive. Trecerea la Zustand a rezolvat problema instant prin selecțiile atomice.
Nu te arunca la librării externe doar pentru că e la modă, dar nici nu te încăpățâna să reinventezi roata cu Context API când ai soluții performante la îndemână. Dacă simți că scrii mai mult cod de infrastructură decât logică de business, e clar că ai nevoie de un store extern.