Гузариш ба мундариҷа
Мавзӯи 9 аз 13
Назария

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 муқоиса кунед: он ҷо коркардкунанда худаш ҳал мекунад, ки ҳолати нав чӣ гуна мешавад. Ин ҷо коркардкунанда танҳо дар бораи рӯйдод хабар медиҳад, ва редюсер ҳал мекунад.

Қоидаҳо барои редюсер

Редюсер бояд функсияи тоза бошад:

  1. Ҳолати воридшударо иваз накунад — массив ё объекти нав баргардонад (мисли useState, вагарна React тағйиротро намебинад).
  2. Таъсироти иловагӣ накунад: дар дохил ҳеҷ дархост, таймер, Math.random() ё Date.now(). id-и тасодуфиро беҳтар аст дар коркардкунанда тавлид карда, дар амал диҳед.
  3. Барои амали номаълум — хато партояд. Хатои чопӣ дар 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) — ҳолати тамоми барнома.

Редюсери ҳисобкунак

Осон+10 XP

Функсияи тозаи counterReducer(state, action)-ро нависед. Ҳолат — объекти { count }. Амалҳо:

  • { type: "increment" } — плюс 1;
  • { type: "decrement" } — минус 1;
  • { type: "add", amount } — плюс amount;
  • { type: "reset" } — count 0 мешавад;
  • ҳар дигараш — Error-ро бо паёми Unknown action: <type> партоед.

Функсия объекти нав бармегардонад ва state-ро иваз намекунад.

counterReducer({ count: 5 }, { type: "increment" })        → { count: 6 }
counterReducer({ count: 5 }, { type: "add", amount: 10 })  → { count: 15 }
counterReducer({ count: 5 }, { type: "jump" })             → Error: Unknown action: jump

Барои ҳал кардани масъалаҳо коннекторро пайваст кун

Коди масъалаҳо дар компютери худат иҷро мешавад — ин аз браузер тезтар ва боэътимодтар аст. Барои ин барномаи ройгони коннектори CodeWithMe лозим аст. Онро як бор пайваст кардан кифоя аст.

Коннекторро дар ин компютер ҷустуҷӯ мекунем…

  1. 1
    Коннекторро барои системаи худ (Windows, macOS ё Linux) зеркашӣ кун.Зеркашии коннекторДар саҳифаи зеркашӣ файлеро интихоб кун, ки дар номаш системаи ту ҳаст, масалан windows-amd64.
  2. 2Онро иҷро кун ва ҷузвдонеро интихоб кун, ки ҳалҳоят дар он ҷо меистанд. Python ва Node.js-ро ӯ худаш ҳангоми зарурат ба он ҷо мегузорад.
  3. 3
    Дар поён рамзи 6-рақамаро ворид кун — он дар равзанаи коннектор навишта шудааст («Рамз барои сайти CodeWithMe»). Агар браузер дар бораи дастрасӣ ба шабакаи маҳаллӣ пурсад — иҷозат деҳ.

Коннектор кушода аст (рамзи манбаъ дар GitHub), танҳо дар компютери ту кор мекунад ва кодро танҳо пас аз ворид кардани рамзи пайвастшавӣ иҷро мекунад.