React useState: holat bilan ishlash
Hodisalar darsi ochiq muammo bilan tugadi: tugma
bosilganda count o’zgarardi, lekin ekran qotib turardi. Sabab ikkita
edi — React o’zgarishdan xabardor bo’lmadi va qiymat qayta chizishda
yo’qoldi. useState ikkalasini ham hal qiladi.
useState — birinchi hook
Muammoli kodni tuzatamiz:
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<p>Bosilgan: {count}</p>
<button type="button" onClick={handleClick}>
Bosish
</button>
</div>
);
}
export default Counter;
Endi tugmani bosing — ekrandagi raqam oshadi.
useState nima qaytaradi
useState ikki elementli massiv qaytaradi:
const [count, setCount] = useState(0);
| Element | Nima |
|---|---|
count |
Joriy qiymat |
setCount |
Qiymatni o’zgartiradigan funksiya |
useState(0) dagi 0 |
Boshlang’ich qiymat |
Kvadrat qavs — massiv destructuring.
Nomlarni o’zingiz tanlaysiz, lekin kelishuv qat’iy: qiymat x bo’lsa,
funksiya setX.
const [name, setName] = useState("");
const [isOpen, setIsOpen] = useState(false);
const [tasks, setTasks] = useState([]);
const [user, setUser] = useState(null);
Boshlang’ich qiymat faqat birinchi chizishda ishlatiladi. Keyingi
chizishlarda useState saqlangan qiymatni qaytaradi — shuning uchun
raqam nolga qaytmaydi.
Qayta chizish qanday ishlaydi
setCount chaqirilganda ketma-ketlik shunday:
- React yangi qiymatni yozib qo’yadi.
- Komponent funksiyasini qaytadan chaqiradi.
- Bu safar
useStateyangi qiymatni qaytaradi. - Yangi JSX hosil bo’ladi va eskisi bilan solishtiriladi.
- DOM’da faqat farq o’zgartiriladi.
Muhim natija: komponent funksiyasi ko’p marta ishlaydi. Har bosishda
Counter funksiyasi boshidan oxirigacha qayta bajariladi. Shuning uchun
uning ichida og’ir hisob yozmaslik kerak.
Holatni to’g’ridan-to’g’ri o’zgartirmang
Bu qoidaning buzilishi eng ko’p uchraydigan React xatosi:
// ❌ Ishlamaydi
function handleClick() {
count++;
}
// ❌ Bu ham ishlamaydi
function handleClick() {
count = count + 1;
}
// ✅ To'g'ri
function handleClick() {
setCount(count + 1);
}
count — oddiy const o’zgaruvchi. Uni o’zgartirish React’ga hech nima
demaydi. Faqat setCount chaqiruvi qayta chizishni boshlaydi.
Oldingi qiymatga tayanish
Yuqoridagi xususiyat aniq muammoga olib keladi. Tugmani bir bosishda ikki marta oshirmoqchi bo’lsangiz:
// ❌ Bir marta oshadi
function handleDoubleClick() {
setCount(count + 1);
setCount(count + 1);
}
count 0 bo’lsa, ikkala qator ham setCount(1) ga aylanadi. Natija
1, 2 emas.
Yechim — set funksiyasiga qiymat emas, funksiya berish:
// ✅ Ikki marta oshadi
function handleDoubleClick() {
setCount((previousCount) => previousCount + 1);
setCount((previousCount) => previousCount + 1);
}
Bunday yozuvda React har chaqiruvga eng oxirgi qiymatni beradi.
Birinchisi 0 olib 1 qaytaradi, ikkinchisi 1 olib 2 qaytaradi.
Bir necha holat
Komponentda useState ni xohlagancha chaqirish mumkin:
import { useState } from 'react';
function TaskForm() {
const [title, setTitle] = useState("");
const [priority, setPriority] = useState(1);
const [isUrgent, setIsUrgent] = useState(false);
return (
<div>
<p>Nomi: {title || "(bo'sh)"}</p>
<p>Muhimlik: {priority}</p>
<p>Shoshilinch: {isUrgent ? "ha" : "yo'q"}</p>
<button type="button" onClick={() => setIsUrgent(!isUrgent)}>
Shoshilinchni almashtirish
</button>
</div>
);
}
export default TaskForm;
Tugma bosilganda faqat “Shoshilinch” qatori o’zgaradi — qolgan holatlar joyida qoladi.
Har holat mustaqil. Bog’liq bo’lmagan ma’lumotlarni alohida saqlang — bitta katta obyektga tiqishdan ko’ra shunday qilish o’qishga qulay.
Obyekt holati
Holat obyekt bo’lsa, uni o’zgartirmang — yangi nusxa yasang:
const [user, setUser] = useState({ name: "Aziz", city: "Toshkent" });
// ❌ React o'zgarishni sezmaydi
function handleRename() {
user.name = "Bobur";
setUser(user);
}
// ✅ Yangi obyekt
function handleRename() {
setUser({ ...user, name: "Bobur" });
}
Birinchi variant ishlamaydi, chunki React eski va yangi qiymatni solishtirganda bir xil obyekt ko’radi: manzil o’zgarmagan, demak o’zgarish yo’q deb hisoblaydi.
{ ...user, name: "Bobur" } esa yangi obyekt: user ning barcha
maydonlari ko’chiriladi, name esa yangisiga almashtiriladi.
// asl: { name: "Aziz", city: "Toshkent" }
// yangi: { name: "Bobur", city: "Toshkent" }
Bu funksional dasturlash darsidagi o’zgarmaslik qoidasi. React shunga tayanadi.
Massiv holati
Massivda ham xuddi shu mantiq. push, splice, sort — hammasi asl
massivni o’zgartiradi, demak yaramaydi.
Uchta asosiy amal:
const [tasks, setTasks] = useState([
{ id: 1, title: "Non olish", isDone: false },
{ id: 2, title: "Kitob o'qish", isDone: false },
]);
Qo’shish — spread bilan:
function handleAdd() {
const newTask = {
id: crypto.randomUUID(),
title: "Yangi vazifa",
isDone: false,
};
setTasks([...tasks, newTask]);
}
O’chirish — filter bilan:
function handleDelete(taskId) {
setTasks(tasks.filter((task) => task.id !== taskId));
}
O’zgartirish — map bilan:
function handleToggle(taskId) {
setTasks(
tasks.map((task) =>
task.id === taskId ? { ...task, isDone: !task.isDone } : task
)
);
}
Oxirgisini o’qing: har vazifa uchun id tekshiriladi. Mos kelsa yangi
obyekt qaytariladi (isDone teskarisiga o’zgargan), mos kelmasa
vazifaning o’zi qoladi.
Qulay jadval:
| Amal | Ishlating | Ishlatmang |
|---|---|---|
| Qo’shish | [...tasks, newTask] |
tasks.push() |
| Boshiga qo’shish | [newTask, ...tasks] |
tasks.unshift() |
| O’chirish | tasks.filter(...) |
tasks.splice() |
| O’zgartirish | tasks.map(...) |
tasks[0].isDone = true |
| Saralash | [...tasks].sort(...) |
tasks.sort() |
To’liq misol
Hamma narsani birlashtiramiz:
// src/App.jsx
import { useState } from 'react';
function App() {
const [tasks, setTasks] = useState([
{ id: 1, title: "Non olish", isDone: false },
{ id: 2, title: "Kitob o'qish", isDone: true },
]);
function handleToggle(taskId) {
setTasks(
tasks.map((task) =>
task.id === taskId ? { ...task, isDone: !task.isDone } : task
)
);
}
function handleDelete(taskId) {
setTasks(tasks.filter((task) => task.id !== taskId));
}
function handleAdd() {
const newTask = {
id: crypto.randomUUID(),
title: "Yangi vazifa",
isDone: false,
};
setTasks([...tasks, newTask]);
}
const activeCount = tasks.filter((task) => !task.isDone).length;
return (
<div>
<h1>Vazifalar</h1>
<p>Bajarilmagan: {activeCount}</p>
<button type="button" onClick={handleAdd}>
Qo'shish
</button>
<ul>
{tasks.map((task) => (
<li key={task.id}>
<input
type="checkbox"
checked={task.isDone}
onChange={() => handleToggle(task.id)}
/>
<span className={task.isDone ? "done" : "active"}>
{task.title}
</span>
<button type="button" onClick={() => handleDelete(task.id)}>
O'chirish
</button>
</li>
))}
</ul>
</div>
);
}
export default App;
Brauzerda sinab ko’ring: checkbox belgilansa matn ko’rinishi o’zgaradi, “O’chirish” qator yo’qotadi, “Qo’shish” yangi qator qo’shadi. Va har amalda “Bajarilmagan” raqami o’zi to’g’rilanadi.
React nima darsidagi muammoni eslang: qo’lda DOM
boshqarishda hisoblagichni yangilashni unutish mumkin edi. Bu yerda
activeCount har chizishda tasks dan hisoblanadi, demak uni unutish
imkonsiz.
Amaliy mashq
CounterkomponentiniuseStatebilan yozing va tugma bosilganda ekrandagi raqam oshishini tekshiring.handleClickichidasetCount(count + 1)dan keyinconsole.log(count)qo’ying — eski qiymat chiqishini ko’ring.- Bitta ishlovchi ichida
setCount(count + 1)ni ikki marta yozing, raqam nechtaga oshganini sanang. Keyin funksiya shakliga o’tkazing va farqni ko’ring. isOpennomli mantiqiy holat yarating, tugma bilan uni almashtiring:setIsOpen(!isOpen).- Yuqoridagi to’liq misolni loyihangizga ko’chiring va uchta amalni ham sinab ko’ring.
handleAddichidasetTasks([...tasks, newTask])o’rnigatasks.push(newTask); setTasks(tasks);yozing. Ekranda hech nima o’zgarmasligini ko’ring, keyin qaytaring.
3-va 6-qadamlar React’dagi ikki asosiy chalkashlikni ko’rsatadi: holatning kechikib yangilanishi va o’zgarmaslik talabi.
Qisqacha xulosa
useStatekomponentga o’zgaruvchan holat qo’shadi va[value, setValue]juftligini qaytaradi.- Boshlang’ich qiymat faqat birinchi chizishda ishlatiladi.
- Faqat
setfunksiyasi qayta chizishni boshlaydi — o’zgaruvchini to’g’ridan-to’g’ri o’zgartirish hech nima qilmaydi. setchaqirilgandan keyin qiymat darrov o’zgarmaydi; yangisi keyingi chizishda keladi.- Yangi qiymat eskisiga bog’liq bo’lsa funksiya shaklini ishlating:
setCount((previous) => previous + 1). - Obyekt va massiv holatini o’zgartirmang —
{ ...user },[...tasks],map,filterbilan yangi nusxa yasang. - Hook’lar komponentning eng yuqorisida, shart va sikl ichisiz chaqiriladi.
Keyingi darsda forma va boshqariladigan elementlar — foydalanuvchidan matn qabul qilish.