useReducer — nima, useState dan farqi, qachon ishlatiladi
Muammo: useState murakkablashib ketganda
Vazifalar ilovasini yozyapsiz. Qo'shish, o'chirish, bajarildi belgilash, hammasini tozalash — to'rtta amal. useState bilan:
function VazifaIlovasi() {
const [vazifalar, setVazifalar] = useState([]);
function qoshish(matn) {
setVazifalar([...vazifalar, { id: Date.now(), matn, bajarildi: false }]);
}
function ochirish(id) {
setVazifalar(vazifalar.filter(v => v.id !== id));
}
function toggle(id) {
setVazifalar(vazifalar.map(v =>
v.id === id ? { ...v, bajarildi: !v.bajarildi } : v
));
}
function hammasiniTozala() {
setVazifalar([]);
}
}
Ishlaydi. Lekin muammo bor: state ni qanday o'zgartirish kerakligi — qoshish, ochirish, toggle, hammasiniTozala — komponent ichida tarqalib yotibdi. Komponent o'sib borsa, bu mantiqni topish va o'zgartirish qiyinlashadi.
useReducer — bu mantiqni alohida joyga chiqaradi. Komponent faqat "qaysi amal bajarildi" deydi — qanday o'zgarishini boshqa joy hal qiladi.
useReducer qanday ishlaydi?
useState da siz yangi qiymatni to'g'ridan-to'g'ri berasiz:
setVazifalar([...vazifalar, yangiVazifa]);
useReducer da siz faqat "nima bo'ldi" ni aytasiz:
dispatch({ type: 'QOSHISH', payload: yangiVazifa });
"Qanday o'zgarish" ni esa reducer funksiyasi hal qiladi. Bu funksiya alohida yoziladi.
dispatch({ type: 'QOSHISH' })
│
▼
reducer(hozirgiState, action) ← bu funksiya hal qiladi
│
▼
yangiState → komponent qayta chiziladi
Amaliy misol
Avval reducer funksiyasini yozamiz — bu komponentdan tashqarida:
function vazifaReducer(state, action) {
switch (action.type) {
case 'QOSHISH':
// yangi vazifa qo'shish
return [...state, { id: Date.now(), matn: action.payload, bajarildi: false }];
case 'OCHIRISH':
// id bo'yicha o'chirish
return state.filter(v => v.id !== action.payload);
case 'TOGGLE':
// bajarildi holatini o'zgartirish
return state.map(v =>
v.id === action.payload ? { ...v, bajarildi: !v.bajarildi } : v
);
case 'TOZALA':
return [];
default:
return state; // noma'lum action — o'zgartirmay qaytarish
}
}
Endi komponentda ishlatamiz:
function VazifaIlovasi() {
const [vazifalar, dispatch] = useReducer(vazifaReducer, []);
const [yangiMatn, setYangiMatn] = useState('');
return (
<div>
<input
value={yangiMatn}
onChange={e => setYangiMatn(e.target.value)}
placeholder="Yangi vazifa..."
/>
<button onClick={() => {
dispatch({ type: 'QOSHISH', payload: yangiMatn });
setYangiMatn('');
}}>
Qo'shish
</button>
<button onClick={() => dispatch({ type: 'TOZALA' })}>
Hammasini tozala
</button>
<ul>
{vazifalar.map(v => (
<li key={v.id}>
<input
type="checkbox"
checked={v.bajarildi}
onChange={() => dispatch({ type: 'TOGGLE', payload: v.id })}
/>
<span>{v.matn}</span>
<button onClick={() => dispatch({ type: 'OCHIRISH', payload: v.id })}>
✕
</button>
</li>
))}
</ul>
</div>
);
}
Komponent endi faqat "qaysi tugma bosildi" ni aytadi. Qanday o'zgarishini vazifaReducer hal qiladi. Ikkalasi alohida — ikkalasini alohida o'qish, alohida o'zgartirish mumkin.
useState vs useReducer — qachon qaysi?
useState:
✅ Oddiy qiymat — son, string, boolean
✅ 1-2 ta bog'liq bo'lmagan o'zgarish
✅ Kichik komponent
useReducer:
✅ Bir-biriga bog'liq bir nechta o'zgarish
✅ Mantiq murakkab — ko'p shartlar
✅ Mantiqni komponentdan ajratish kerak
✅ Reducer ni alohida test qilish kerak
Oddiy qoida: agar setXxx ni chaqirishdan oldin "avval holatni tekshirish, keyin boshqa state ni ham o'zgartirish" kerak bo'lsa — useReducer vaqti keldi.
Reducer — sof funksiya
Reducer haqida bitta muhim qoida: u sof funksiya bo'lishi kerak.
Sof funksiya degani:
- Bir xil kirish → har doim bir xil chiqish
- Tashqariga ta'sir qilmaydi (API chaqirmaydi, DOM o'zgartirmaydi)
stateni to'g'ridan-to'g'ri o'zgartirmaydi
// ❌ Xato — state ni to'g'ridan-to'g'ri o'zgartirdi
function reducer(state, action) {
state.push(action.payload); // mutatsiya!
return state; // xuddi shu ob'ekt — React farq ko'rmaydi
}
// ✅ To'g'ri — yangi massiv qaytaradi
function reducer(state, action) {
return [...state, action.payload];
}
Nima uchun? React state ni reference bo'yicha solishtiradi. Eski ob'ektni o'zgartirsangiz — React "hech narsa o'zgarmadi" deb o'ylaydi, ekran yangilanmaydi.
Xulosa
useReducer — murakkab state uchun useState ning kuchliroq varianti.
useState: setQiymat(yangi) → oddiy
useReducer: dispatch({ type }) → murakkab, tartibli
Reducer: (state, action) → yangiState
sof funksiya, alohida yoziladi
Komponent faqat "nima bo'ldi" ni aytadi. "Qanday o'zgarish" ni reducer hal qiladi. Bu ikki narsani ajratish — katta loyihalarda juda muhim.
Keyingi dars
20-dars: useReducer — action, dispatch, reducer funksiya