React: holatni ko'tarish
Serverdan ma’lumot yuklash darsida ro’yxat bitta komponentda edi. Endi ilovaga qidiruv maydoni va “topildi: N ta” hisoblagichi qo’shilsin. Ular alohida komponentlar, lekin bitta ma’lumotga tayanadi. Holatni ko’tarish shu vaziyat uchun.
Muammo: ikki komponent bir-birini ko’rmaydi
Ikkita komponent yozamiz. SearchInput qidiruv matnini saqlaydi,
TaskList esa ro’yxatni filtrlashi kerak:
// ❌ Bu tuzilma ishlamaydi
import { useState } from 'react';
function SearchInput() {
const [query, setQuery] = useState("");
return (
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Qidirish"
/>
);
}
function TaskList({ tasks }) {
// query bu yerda kerak, lekin uni olishning iloji yo'q
return (
<ul>
{tasks.map((task) => (
<li key={task.id}>{task.title}</li>
))}
</ul>
);
}
function App() {
const tasks = [
{ id: 1, title: "Non olish" },
{ id: 2, title: "Kitob o'qish" },
];
return (
<div>
<SearchInput />
<TaskList tasks={tasks} />
</div>
);
}
export default App;
Maydonga yozsangiz matn ko’rinadi, lekin ro’yxat qimirlamaydi.
Sabab — query SearchInput ning ichida qulflangan.
Props darsidagi qoidani eslang: ma’lumot faqat
yuqoridan pastga oqadi. TaskList — SearchInput ning bolasi
emas, ukasi. Ular orasida hech qanday yo’l yo’q.
App
├── SearchInput ← query bu yerda
└── TaskList ← query bu yerda kerak
Yechim: holatni yuqoriga ko’chirish
query ni App ga olib chiqamiz:
import { useState } from 'react';
function SearchInput({ query, onQueryChange }) {
return (
<input
type="text"
value={query}
onChange={(e) => onQueryChange(e.target.value)}
placeholder="Qidirish"
/>
);
}
function TaskList({ tasks }) {
if (tasks.length === 0) {
return <p>Mos vazifa topilmadi.</p>;
}
return (
<ul>
{tasks.map((task) => (
<li key={task.id}>{task.title}</li>
))}
</ul>
);
}
function App() {
const [query, setQuery] = useState("");
const tasks = [
{ id: 1, title: "Non olish" },
{ id: 2, title: "Kitob o'qish" },
{ id: 3, title: "Kitob qaytarish" },
];
const visibleTasks = tasks.filter((task) =>
task.title.toLowerCase().includes(query.toLowerCase())
);
return (
<div>
<SearchInput query={query} onQueryChange={setQuery} />
<p>Topildi: {visibleTasks.length} ta</p>
<TaskList tasks={visibleTasks} />
</div>
);
}
export default App;
Maydonga “kitob” deb yozing — ro’yxatda ikkita vazifa qoladi va
hisoblagich 2 ni ko’rsatadi. Uchalasi bir vaqtda yangilanadi.
Endi tuzilma shunday:
App ← query holati
├── SearchInput ← query (o'qish) + onQueryChange (yozish)
├── <p>Topildi</p> ← visibleTasks.length
└── TaskList ← visibleTasks
Ikki yo’nalishli bog’lanish
Bola holatni o’zgartira olmaydi, lekin o’zgartirishni so’rashi mumkin. Buning uchun ota-komponent unga funksiya beradi:
// Pastga: qiymat
<SearchInput query={query} onQueryChange={setQuery} />
// ↑ o'qish ↑ yozish huquqi
Aylanish shunday ishlaydi:
Appqueryni vasetQueryniSearchInputga beradi.- Foydalanuvchi harf yozadi.
SearchInputonQueryChange(newQuery)ni chaqiradi.- Bu aslida
AppdagisetQuery— holat o’zgaradi. Appqayta chiziladi va yangiqueryni pastga uzatadi.
To’liq misol: vazifalar ilovasi
Bir necha komponent bitta ro’yxat bilan ishlaydi:
// src/components/TaskItem.jsx
function TaskItem({ task, onToggle, onDelete }) {
return (
<li>
<input
type="checkbox"
checked={task.isDone}
onChange={() => onToggle(task.id)}
/>
<span className={task.isDone ? "done" : "active"}>{task.title}</span>
<button type="button" onClick={() => onDelete(task.id)}>
O'chirish
</button>
</li>
);
}
export default TaskItem;
// src/components/TaskList.jsx
import TaskItem from './TaskItem.jsx';
function TaskList({ tasks, onToggle, onDelete }) {
if (tasks.length === 0) {
return <p>Vazifa yo'q.</p>;
}
return (
<ul>
{tasks.map((task) => (
<TaskItem
key={task.id}
task={task}
onToggle={onToggle}
onDelete={onDelete}
/>
))}
</ul>
);
}
export default TaskList;
// src/components/TaskForm.jsx
import { useState } from 'react';
function TaskForm({ onAdd }) {
const [title, setTitle] = useState("");
function handleSubmit(e) {
e.preventDefault();
if (title.trim() === "") return;
onAdd(title.trim());
setTitle("");
}
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="Yangi vazifa"
/>
<button type="submit">Qo'shish</button>
</form>
);
}
export default TaskForm;
// src/App.jsx
import { useState } from 'react';
import TaskForm from './components/TaskForm.jsx';
import TaskList from './components/TaskList.jsx';
function App() {
const [tasks, setTasks] = useState([
{ id: 1, title: "Non olish", isDone: false },
{ id: 2, title: "Kitob o'qish", isDone: true },
]);
function handleAdd(title) {
const newTask = { id: crypto.randomUUID(), title, isDone: false };
setTasks([...tasks, newTask]);
}
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));
}
const activeCount = tasks.filter((task) => !task.isDone).length;
return (
<div>
<h1>Vazifalar</h1>
<p>Bajarilmagan: {activeCount}</p>
<TaskForm onAdd={handleAdd} />
<TaskList tasks={tasks} onToggle={handleToggle} onDelete={handleDelete} />
</div>
);
}
export default App;
Brauzerda sinang: vazifa qo’shing, belgilang, o’chiring. Hisoblagich har amalda o’zi to’g’rilanadi.
Diqqat qiling: tasks ni faqat App o’zgartiradi. Qolgan komponentlar
ma’lumotni ko’rsatadi va o’zgartirishni so’raydi.
TaskForm nega o’z holatini saqlaydi
Diqqatli o’quvchi savol beradi: TaskForm ichida title holati bor —
bu qoidaga zid emasmi?
Yo’q. title — faqat formaning o’ziga tegishli vaqtinchalik
ma’lumot. Foydalanuvchi yozib turgan matn boshqa hech kimga kerak emas;
u “Qo’shish” bosilgandagina onAdd orqali yuqoriga uzatiladi.
Qoida shunday:
| Ma’lumot | Qayerda |
|---|---|
| Bir nechta komponentga kerak | Umumiy ota-komponentda |
| Faqat bitta komponentga kerak | O’sha komponentda |
Qachon ko’tarish kerak emas
Holatni keraksiz ko’tarish ham muammo tug’diradi:
1. Ma’lumot faqat bitta komponentniki bo’lsa. Ochiladigan menyuning
isOpen holati, forma maydonining matni, kartochkaning “batafsil”
ko’rinishi — bularni ko’tarish kerak emas.
// ✅ Holat o'z joyida
function Accordion({ title, children }) {
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<button type="button" onClick={() => setIsOpen(!isOpen)}>
{title} {isOpen ? "▲" : "▼"}
</button>
{isOpen && <div>{children}</div>}
</div>
);
}
export default Accordion;
isOpen ni App ga ko’tarsangiz, App har ochish-yopishda qayta
chiziladi va kod sababsiz murakkablashadi.
2. Qiymat mavjud holatdan hisoblanadigan bo’lsa. activeCount
uchun alohida holat kerak emas — u tasks dan hisoblanadi. Bu
shartli ko’rinish darsida aytilgan qoida.
Holatni qayerga qo’yish kerak
Aniq tartib bor:
- Qaysi komponentlar bu ma’lumotga tayanishini aniqlang.
- Ularning eng yaqin umumiy ota-komponentini toping.
- Holatni o’sha yerga qo’ying.
- Qiymatni pastga props bilan uzating.
- O’zgartirish kerak bo’lgan bolalarga funksiya uzating.
Misolda: SearchInput, hisoblagich va TaskList — uchalasining eng
yaqin umumiy otasi App. Demak query App da turadi.
Amaliy mashq
SearchInputvaTaskListni yozing,queryniSearchInputichida qoldiring va ro’yxat filtrlanmasligini ko’ring.queryniAppga ko’taring,SearchInputgaqueryvaonQueryChangeprops bilan uzating.- “Topildi: N ta” hisoblagichini qo’shing va u ham bir vaqtda yangilanishini tekshiring.
- Yuqoridagi to’liq vazifalar ilovasini to’rtta faylga bo’lib yozing:
App,TaskForm,TaskList,TaskItem. TaskFormdagititleholatiniAppga ko’tarib ko’ring va kod qanchalik chalkashganini baholang. Keyin qaytaring.Accordionkomponentini yozing va uningisOpenholati nega ko’tarilmasligi kerakligini bir jumlada tushuntiring.
5-qadam teskari tomonni ko’rsatadi: holatni ko’tarish har doim ham yaxshilik emas, faqat zarurat bo’lganda qilinadi.
Qisqacha xulosa
- Ukalar komponentlar bir-birining holatini ko’ra olmaydi — ma’lumot faqat yuqoridan pastga oqadi.
- Holatni ko’tarish — umumiy ma’lumotni eng yaqin umumiy ota-komponentga ko’chirish.
- Ota-komponent pastga qiymatni va o’zgartirish uchun funksiyani uzatadi.
- Ma’lumot yagona joyda saqlanadi, shuning uchun nusxalari bir-biridan farq qilib qolmaydi.
- Faqat bitta komponentga tegishli holatni (
isOpen, forma maydoni) ko’tarmang. - Mavjud holatdan hisoblanadigan qiymat uchun alohida holat kerak emas.
- Eng yaqin umumiy ota-komponentni tanlang — hammasini
Appga yig’ish kodni og’irlashtiradi.
Keyingi darsda yakuniy loyiha — butun bo’lim bo’ylab o’rganilganlarni bitta ilovada birlashtirasiz.