useReducer: ҳолати мураккаб
Кай useState кифоя нест
То даме ки ҳолат як-ду қимат аст, useState беҳтарин аст. Аммо дар барномаҳои воқеӣ мантиқ зуд калон мешавад:
рӯйхати вазифаҳо, ки онро илова кардан, қайд кардан, нест кардан, филтр кардан, тоза кардан мумкин аст. Коди иваз
кардани ҳолат ба даҳҳо коркардкунанда дар ҷойҳои гуногуни компонент паҳн мешавад, ва фаҳмидан душвор мешавад, ки
ҳолат умуман чӣ тавр тағйир ёфта метавонад.
useReducer тамоми мантиқи тағйиротро ба як функсия — редюсер ҷамъ мекунад. Коркардкунандаҳои рӯйдодҳо дигар
намегӯянд «чӣ тавр иваз кардан», онҳо танҳо хабар медиҳанд, ки чӣ рух дод.
Амалҳо ва редюсер
function tasksReducer(tasks, action) {
switch (action.type) {
case "added":
return [...tasks, { id: action.id, text: action.text, done: false }];
case "toggled":
return tasks.map((t) => (t.id === action.id ? { ...t, done: !t.done } : t));
case "deleted":
return tasks.filter((t) => t.id !== action.id);
default:
throw new Error("Unknown action: " + action.type);
}
}
- Амал (action) — объекти оддӣ, ки рӯйдодро тасвир мекунад. Аз рӯи созишнома он майдони
typeдорад, боқимонда — маълумот:{ type: "deleted", id: 3 }. - Редюсер (reducer) — функсияи
(ҳолатиҶорӣ, амал) → ҳолатиНав. Ном аз усули массивҳоreduceаст: вай ҳам пайдарпайиро ба як қимат «мепечонад».
Редюсерро бе React, мисли функсияи оддӣ санҷидан мумкин аст:
let state = [];
state = tasksReducer(state, { type: "added", id: 1, text: "Нон харидан" });
state = tasksReducer(state, { type: "added", id: 2, text: "Ба модар занг задан" });
state = tasksReducer(state, { type: "toggled", id: 1 });
console.log(state);
useReducer дар компонент
const { useReducer } = React;
function TaskApp() {
const [tasks, dispatch] = useReducer(tasksReducer, []);
return (
<div>
<button onClick={() => dispatch({ type: "added", id: Date.now(), text: "Нав" })}>
Илова кардан
</button>
<ul>
{tasks.map((t) => (
<li key={t.id}>
<span onClick={() => dispatch({ type: "toggled", id: t.id })}>{t.text}</span>
<button onClick={() => dispatch({ type: "deleted", id: t.id })}>×</button>
</li>
))}
</ul>
</div>
);
}
useReducer(редюсер, ҳолатиИбтидоӣ)ҷуфтро бармегардонад: ҳолати ҷорӣ ва функсияиdispatch.dispatch(амал)— «амалро фиристодан». React редюсерро бо ҳолати ҷорӣ ва ҳамин амал даъват мекунад, натиҷаро нигоҳ медорад ва компонентро аз нав мекашад.
Бо useState муқоиса кунед: он ҷо коркардкунанда худаш ҳал мекунад, ки ҳолати нав чӣ гуна мешавад. Ин ҷо
коркардкунанда танҳо дар бораи рӯйдод хабар медиҳад, ва редюсер ҳал мекунад.
Қоидаҳо барои редюсер
Редюсер бояд функсияи тоза бошад:
- Ҳолати воридшударо иваз накунад — массив ё объекти нав баргардонад (мисли
useState, вагарна React тағйиротро намебинад). - Таъсироти иловагӣ накунад: дар дохил ҳеҷ дархост, таймер,
Math.random()ёDate.now(). id-и тасодуфиро беҳтар аст дар коркардкунанда тавлид карда, дар амал диҳед. - Барои амали номаълум — хато партояд. Хатои чопӣ дар
typeфавран намоён мешавад.
Тозагӣ бартарии калон медиҳад: натиҷа танҳо аз вуруд вобаста аст, барои ҳамин редюсерро санҷидан осон аст, ва рафтори барномаро бо такрори ҳамон амалҳо такрор кардан мумкин аст.
Агар дар case тағйирёбанда эълон кардан лозим бошад, онро ба қавсҳои фигурӣ печонед — ҳамин тавр тағйирёбандаҳои
шохаҳои гуногун бо ҳам бархӯрд намекунанд:
case "added": {
const id = Math.max(0, ...tasks.map((t) => t.id)) + 1;
return [...tasks, { id, text: action.text, done: false }];
}
useState ё useReducer?
useState |
useReducer |
|
|---|---|---|
| Ҳаҷми код | камтар | бештар (редюсер + амалҳо) |
| Қиматҳои содда (байрақ, матни майдон) | ✓ | зиёдатӣ |
| Роҳҳои бисёри иваз кардани як ҳолат | коркардкунандаҳо паҳн мешаванд | тамоми мантиқ дар як ҷо |
| Санҷиши мантиқ | якҷоя бо компонент | редюсер — алоҳида, ҳамчун функсия |
| Ислоҳи хатоҳо | — | ҳар амалро ба консол баровардан мумкин аст |
Қоидаи хуб: бо useState сар кунед. Агар коркардкунандаҳое, ки ҳамон як ҳолатро иваз мекунанд, бисёр шаванд — ба
useReducer гузаред. Ин кардан осон аст: амалҳо он чиро тасвир мекунанд, ки дар коркардкунандаҳо аллакай рух медиҳад.
Редюсер + контекст
useReducer ва useContext якҷоя — нақшаи стандартӣ барои ҳолати тамоми барнома бе китобхонаҳои берунӣ:
const TasksContext = createContext(null);
const DispatchContext = createContext(null);
function TasksProvider({ children }) {
const [tasks, dispatch] = useReducer(tasksReducer, []);
return (
<TasksContext.Provider value={tasks}>
<DispatchContext.Provider value={dispatch}>
{children}
</DispatchContext.Provider>
</TasksContext.Provider>
);
}
function DeleteButton({ id }) {
const dispatch = useContext(DispatchContext);
return <button onClick={() => dispatch({ type: "deleted", id })}>×</button>;
}
- Ҳолат ва мантиқ — дар як ҷо (
TasksProvider+ редюсер). - Ҳар компонент дар ҳар чуқурӣ вазифаҳоро мехонад (
TasksContext) ё амалҳо мефиристад (DispatchContext), бе props. - Чаро ду контекст? Функсияи
dispatchҳеҷ гоҳ тағйир намеёбад, барои ҳамин компонентҳое, ки танҳоdispatchлозим доранд (тугмаҳо), ҳангоми ҳар тағйири рӯйхат аз нав кашида намешаванд.
Китобхонаҳои маъмули ҳолат — Redux ва Zustand — ба ҳамин монанд сохта шудаанд: анбор, амалҳо ва функсияҳои тозаи
навсозӣ. useReducer-ро фаҳмида, онҳоро ҳам мефаҳмед.
Хулоса
useReducer(reducer, initial)→[state, dispatch].- Амал — объекти
{ type, ...маълумот }, тасвир мекунад, ки чӣ рух дод. - Редюсер — функсияи тозаи
(state, action) => newState: бе мутатсия ва эффектҳо, амали номаълум — хато. useState— барои содда,useReducer— вақте роҳҳои иваз кардани ҳолат бисёранд.- Редюсер + ду контекст (ҳолат ва
dispatch) — ҳолати тамоми барнома.