useReducer — action, dispatch, reducer funksiya

~20 daq · React · Hooks — Ilg'or

Action nima?

Oldingi darsda dispatch({ type: 'QOSHISH', payload: ... }) yozdik. Keling, bu tushunchalarni chuqurroq ko'ramiz.

Action — "nima bo'ldi" ni tasvirlovchi oddiy ob'ekt. Xuddi xabar kabi: "foydalanuvchi qo'shish tugmasini bosdi, mana ma'lumot".

{
  type: 'QOSHISH',     ← nima bo'ldi (majburiy)
  payload: 'Matn'      ← qo'shimcha ma'lumot (ixtiyoriy)
}

type — har doim string. Odatda KATTA_HARF bilan yoziladi — bu konventsiya, majburiy emas. Lekin katta loyihalarda KATTA_HARF yozilgan action ni ko'rganingizda darhol "bu action" deb bilasiz.

payload — action bilan birga keladigan ma'lumot. Har xil nom ishlatish mumkin, lekin payload — keng tarqalgan standart.


Reducer funksiyasini chuqurroq tushunish

Reducer — switch/case bilan yoziladi. Har bir case — bitta action turi uchun javob.

function hisoblagichReducer(state, action) {
  switch (action.type) {

    case 'OSHIR':
      // qadam bo'yicha oshirish — payload da qadam bor
      return { ...state, son: state.son + action.payload };

    case 'KAMAYTIR':
      return { ...state, son: state.son - action.payload };

    case 'NOLGA_QAYTARISH':
      // payload kerak emas
      return { ...state, son: 0 };

    case 'QADAM_OZGARTIR':
      return { ...state, qadam: action.payload };

    default:
      // Noma'lum action — state ni o'zgartirmay qaytarish
      // Bu muhim — xato action yuborilganda state buzilmasin
      return state;
  }
}
function Hisoblagich() {
  const [state, dispatch] = useReducer(hisoblagichReducer, { son: 0, qadam: 1 });

  return (
    <div>
      <p>Son: {state.son}</p>

      <button onClick={() => dispatch({ type: 'OSHIR', payload: state.qadam })}>
        +{state.qadam}
      </button>

      <button onClick={() => dispatch({ type: 'KAMAYTIR', payload: state.qadam })}>
        -{state.qadam}
      </button>

      <button onClick={() => dispatch({ type: 'NOLGA_QAYTARISH' })}>
        Nolga qaytarish
      </button>

      <label>
        Qadam:
        <input
          type="number"
          value={state.qadam}
          onChange={e => dispatch({ type: 'QADAM_OZGARTIR', payload: +e.target.value })}
        />
      </label>
    </div>
  );
}

Komponent faqat "qaysi tugma bosildi, qanday qiymat bilan" deydi. Hisoblash mantiqi — reducerda.


Murakkab state — forma misoli

useReducer ning kuchi murakkab formalar bilan ishlashda ko'rinadi. Forma yuborilayotganda bir vaqtda bir nechta state o'zgaradi: loading boshlanadi, xato tozalanadi. Muvaffaqiyatda forma tozalanadi. Xatoda loading to'xtaydi, xato ko'rsatiladi.

const boshlangich = {
  ism: '',
  email: '',
  yuklanmoqda: false,
  xato: null,
  muvaffaqiyat: false,
};

function formaReducer(state, action) {
  switch (action.type) {

    case 'MAYDON_OZGARTIR':
      return {
        ...state,
        [action.payload.maydon]: action.payload.qiymat,
        xato: null, // yozayotganda xatoni tozala
      };

    case 'YUBORISH_BOSHLANDI':
      // bir vaqtda ikki narsa o'zgaradi
      return { ...state, yuklanmoqda: true, xato: null };

    case 'YUBORISH_MUVAFFAQIYAT':
      return { ...boshlangich, muvaffaqiyat: true }; // formani tozala

    case 'YUBORISH_XATO':
      return { ...state, yuklanmoqda: false, xato: action.payload };

    default:
      return state;
  }
}

useState bilan bu to'rtta alohida set funksiyasi bo'lardi. useReducer bilan — bitta dispatch, bir joyda boshqariladi.

function Forma() {
  const [state, dispatch] = useReducer(formaReducer, boshlangich);

  async function yuborish(e) {
    e.preventDefault();
    dispatch({ type: 'YUBORISH_BOSHLANDI' });

    try {
      await fetch('/api/register', {
        method: 'POST',
        body: JSON.stringify({ ism: state.ism, email: state.email }),
      });
      dispatch({ type: 'YUBORISH_MUVAFFAQIYAT' });
    } catch (err) {
      dispatch({ type: 'YUBORISH_XATO', payload: err.message });
    }
  }

  if (state.muvaffaqiyat) return <p>✅ Muvaffaqiyatli ro'yxatdan o'tdingiz!</p>;

  return (
    <form onSubmit={yuborish}>
      {state.xato && <p style={{ color: 'red' }}>{state.xato}</p>}

      <input
        value={state.ism}
        onChange={e => dispatch({
          type: 'MAYDON_OZGARTIR',
          payload: { maydon: 'ism', qiymat: e.target.value },
        })}
        placeholder="Ism"
      />

      <input
        value={state.email}
        onChange={e => dispatch({
          type: 'MAYDON_OZGARTIR',
          payload: { maydon: 'email', qiymat: e.target.value },
        })}
        placeholder="Email"
      />

      <button disabled={state.yuklanmoqda}>
        {state.yuklanmoqda ? 'Yuborilmoqda...' : 'Ro\'yxatdan o\'tish'}
      </button>
    </form>
  );
}

Reducer ni alohida faylga chiqarish

Reducer alohida faylda bo'lsa — uni alohida test qilish mumkin. Komponent faqat UI bilan shug'ullanadi.

src/
├── reducers/
│   └── vazifaReducer.js   ← mantiq shu yerda
└── components/
    └── VazifaIlovasi.jsx  ← faqat UI
// reducers/vazifaReducer.js
export const boshlangich = [];

export function vazifaReducer(state, action) {
  switch (action.type) {
    case 'QOSHISH':
      return [...state, { id: Date.now(), matn: action.payload, bajarildi: false }];
    case 'OCHIRISH':
      return state.filter(v => v.id !== action.payload);
    case 'TOGGLE':
      return state.map(v =>
        v.id === action.payload ? { ...v, bajarildi: !v.bajarildi } : v
      );
    default:
      return state;
  }
}
// components/VazifaIlovasi.jsx
import { useReducer } from 'react';
import { vazifaReducer, boshlangich } from '../reducers/vazifaReducer';

function VazifaIlovasi() {
  const [vazifalar, dispatch] = useReducer(vazifaReducer, boshlangich);
  // ...
}

Xulosa

Action:   { type: 'AMAL', payload: ... }
          "nima bo'ldi" + "qo'shimcha ma'lumot"

Dispatch: dispatch(action)
          "mana, shu bo'ldi"

Reducer:  (state, action) => yangiState
          "shu bo'lganda, shunday o'zgartir"
  • type — KATTA_HARF konventsiya
  • default — har doim bo'lishi kerak
  • Reducer — sof funksiya, alohida faylda saqlash mumkin
  • Bir vaqtda bir nechta state o'zgarishi kerak bo'lsa — useReducer kuchliroq

Keyingi dars

21-dars: useReducer + useContext — o'z state manager ini yozish