Redux Toolkit
Store, acțiuni, reduceri, createSlice cu Immer și Redux în Next.
Actualizat
Ce este Redux
Redux e un model de state global cu reguli stricte:
- Tot state-ul global stă într-un singur store.
- State-ul nu se modifică direct — trimiți (dispatch) o acțiune: un obiect care descrie ce s-a întâmplat (
{ type: 'cart/add', payload: item }). - Un reducer — funcție pură
(state, action) => newState— calculează noul state.
UIdispatch(action)acțiune→reducer(state, action) => newStatestate nou→storeselector→UIse re-randeazăAvantajul: orice schimbare trece prin același loc → previzibil, testabil, cu DevTools care îți arată fiecare acțiune și pot „derula înapoi” istoria.
Redux Toolkit (RTK) e felul oficial și actual de a scrie Redux. Redux „clasic” (cu switch, constante de tip, connect) e considerat depășit.
Piesele Redux Toolkit
| Piesă | Ce face |
|---|---|
configureStore |
creează store-ul, cu DevTools și middleware incluse |
createSlice |
definește o bucată de state + reducerii ei; generează acțiunile automat |
useSelector |
citește o bucată din store (componenta se re-randează doar când ea se schimbă) |
useDispatch |
trimite acțiuni |
createAsyncThunk |
logică asincronă (rar azi — pentru date folosești RTK Query) |
| RTK Query | fetch + cache pentru server state — lecția următoare |
Un slice
// entities/cart/model/cart-slice.ts
import { createSlice, type PayloadAction } from '@reduxjs/toolkit'
type CartItem = { id: number; qty: number }
const cartSlice = createSlice({
name: 'cart',
initialState: [] as CartItem[],
reducers: {
added(state, action: PayloadAction<number>) {
const item = state.find(i => i.id === action.payload)
if (item) item.qty++ // „mutație” permisă — vezi Immer
else state.push({ id: action.payload, qty: 1 })
},
removed(state, action: PayloadAction<number>) {
return state.filter(i => i.id !== action.payload)
},
},
})
export const { added, removed } = cartSlice.actions
export const cartReducer = cartSlice.reducerImmer: în createSlice poți scrie cod care pare să modifice state-ul (state.push, item.qty++). RTK folosește librăria Immer, care transformă aceste „mutații” într-un obiect nou, imutabil. Regulile din Referințe și imutabilitate rămân valabile — doar sintaxa e mai scurtă.
Store și hook-uri tipate
// shared/store/store.ts
export const makeStore = () => configureStore({ reducer: { cart: cartReducer } })
export type AppStore = ReturnType<typeof makeStore>
export type RootState = ReturnType<AppStore['getState']>
export type AppDispatch = AppStore['dispatch']
export const useAppSelector = useSelector.withTypes<RootState>()
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()'use client'
const count = useAppSelector(state => state.cart.length)
const dispatch = useAppDispatch()
<button onClick={() => dispatch(added(product.id))}>Adaugă</button>Redux cu Next.js App Router
- Store-ul se creează per request, nu ca variabilă globală de modul — altfel, pe server, datele unui user ajung la altul. De aceea
makeStore()e o funcție. - Îl pui într-un Client Component
StoreProvider('use client'), creat o dată cuuseRef/useState. - Server Components nu pot citi store-ul — ele își iau datele direct.
Când Redux Toolkit
| Da | Nu |
|---|---|
| aplicație mare, multe echipe, reguli stricte utile | aplicație mică / medie |
| logică complexă cu multe tranziții, nevoie de DevTools / time-travel | doar puțin UI state global |
| proiect existent pe Redux | state care e de fapt server state |
Pe scurt
- Redux = un store, acțiuni, reduceri puri; RTK e modul actual de a-l scrie.
createSlice+ Immer = cod scurt, rezultat imutabil.- În Next: store per request, în Client Component; pentru date de server → RTK Query.