Дарси 24 · React Lite (бонус) · анҷоми курс
useEffect + fetch: мини-барнома дар React ва харитаи роҳ
Қариб ҳар барномаи воқеӣ чизеро бор мекунад: рӯйхати молҳо, ҷадвал, профил. Дар React барои ин useEffect ҳаст — ва маҳз бо он навомӯзон аз ҳама бештар хато мекунанд: дархостҳои беохир, ҷавобҳои кӯҳнаи «часпида», экрани холӣ ҳангоми вайроншавии шабака. Имрӯз мо меомӯзем, ки инро дуруст кунем, барномаро бо API ба React интиқол медиҳем ва нақша тартиб медиҳем, ки минбаъд ба куҷо рушд кунем — ба Сатҳи 3 ва Next.js.
Шарҳ додан, ки useEffect кай иҷро мешавад, ва массиви вобастагиҳои дурустро интихоб кардан
Cleanup навиштан: таймерҳо, обунаҳо ва дархостҳоро қатъ кардан
Маълумотро аз API бор кардан ва чор ҳолатро нишон додан: боршавӣ, хато, холӣ, муваффақият
Дархостҳои кӯҳнашударо тавассути AbortController бекор кардан
Ҷустуҷӯро бо debounce ва филтркуниро бе ҳолати зиёдатӣ иҷро кардан
Фаҳмидан, ки Next.js ва компонентҳои серверӣ чиро илова мекунанд, ва нақшаи худро барои 8 ҳафта доштан
Бо ин саҳифа чӣ тавр кор кардан лозим аст
Код бо тугмаи ▶ Иҷро кардан — зинда аст. Блокҳо бо ҷадвали App.jsx ва соҳаи «Пешнамоиш» — мини-барномаҳои React: «Иҷро кардан»-ро пахш кунед, ва барнома дар тарафи рост пайдо мешавад, ва ҳар чизе, ки он тавассути console.log чоп мекунад, — дар консол дар зери он. Оғози аввали блоки React китобхонаҳоро аз интернет бор мекунад, ин якчанд сония мегирад. Дар вазифаҳо «сервери воқеӣ» бо стенд иваз шудааст — функсияи fakeFetch, ки аз рӯи таймер ҷавоб медиҳад: ин тавр натиҷа ҳамеша якхела аст ва худкор санҷида мешавад. Як мисоли зинда дар поён ба API-и воқеӣ мераваду — он бе санҷиши худкор аст.
Фарз мекунем, ки Шумо бо дарсҳои 22–23 шинос ҳастед: компонент — функсияест, ки JSX бармегардонад, useState маълумотро нигоҳ медорад, .map() бо key рӯйхатҳоро мекашад. Бо fetch, promise-ҳо ва AbortController Шумо дар дарсҳои 13–16 кор кардед.
01 useEffect: кай кор мекунад
Компоненти React — функсияи тоза аст: маълумотро (props ва state) гирифт, тавсифи экранро (JSX) баргардонд. Тамом. Рендер набояд дар ҷаҳони беруна чизеро «кунад»: дархост фиристад, таймер оғоз кунад, сарлавҳаи ҷадвалро тағйир диҳад. Чунин амалҳо таъсироти ҷонибӣ номида мешаванд, ва барои онҳо дар React ҷои алоҳида ҳаст — ҳуки useEffect.
Монанд аз ҳаёт
Дар чойхона пешхизмат аввал дастархон мепӯшад — ин рендер аст: дастархон, пиёлаҳо, нон. Танҳо вақте ки миз тайёр аст, ӯ барои чойник ба ошхона меравад — ин эффект аст. Дар миёнаи тайёр кардани миз ба ошхона рафтан мумкин нест: меҳмон аллакай менишинад ва ба мизи холӣ менигарад. React ҳамин тавр мекунад: аввал экранро нишон медиҳад, ва танҳо баъд аз он эффекти Шуморо оғоз мекунад.
Тартиб: рендер → экран → эффект
«Иҷро кардан»-ро пахш кунед, баъд якчанд маротиба ба тугма дар пешнамоиш — ва аз паси консол равед.
Рендер ва эффект · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx
import { useEffect, useState } from "react" ;
export default function App () {
const [count, setCount] = useState (0 );
// Ин бадани компонент — РЕНДЕР: React ҳисоб мекунад, ки экран чӣ тавр бояд намояд
console.log ("1. рендер: считаем JSX, count =" , count);
// Ва ин ЭФФЕКТ аст: React онро танҳо БАЪД аз нав шудани экран даъват мекунад
useEffect (() => {
console.log ("2. эффект: экран обновлён, count =" , count);
});
return <button onClick={() => setCount (count + 1 )}>Нажато: {count}</button>;
}
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Рендер. React функсияи компонентро даъват мекунад ва JSX мегирад. Ҳар як console.log дар бадани компонент дар ҳамин қадам иҷро мешавад.
Коммит. React DOM-и воқеиро нав мекунад — истифодабаранда экрани навро мебинад.
Эффект. React функсияҳоро аз useEffect даъват мекунад. Инҷо ба шабака баромадан, таймер гузоштан ва ба document даст задан бехатар аст.
Массиви вобастагиҳо: эффект кай такрор мешавад
Ҳамчун аргументи дуюм useEffect массиви вобастагиҳоро қабул мекунад. Он ба саволи «пас аз кадом рендерҳо эффектро аз нав оғоз кардан?» ҷавоб медиҳад.
Навишт Кай кор мекунад Истифодаи маъмулӣ useEffect(fn)пас аз ҳар рендер қариб ҳеҷ гоҳ; аксар вақт ин хато аст useEffect(fn, [])як маротиба, пас аз рендери аввал боркунии маълумот ҳангоми кушодан, обуна useEffect(fn, [a, b])пас аз рендери аввал ва ҳар вақте ки a ё b тағйир ёфтанд дархост аз рӯи id ё сатри ҷустуҷӯ
Кӯшиш кунед: тугмаҳои a ва b-ро пахш кунед ва бинед, ки аз се эффект кадомаш вокуниш нишон медиҳад.
Се варианти вобастагиҳо · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx
import { useEffect, useState } from "react" ;
export default function App () {
const [a, setA] = useState (0 );
const [b, setB] = useState (0 );
useEffect (() => {
console.log ("A (без массива): после КАЖДОГО рендера" );
});
useEffect (() => {
console.log ("B ([]): один раз, после первого рендера" );
}, []);
useEffect (() => {
console.log ("C ([a]): изменился a, теперь a =" , a);
}, [a]);
return (
<div style={{ display: "flex" , gap: 8 }}>
<button onClick={() => setA (a + 1 )}>a = {a}</button>
<button onClick={() => setB (b + 1 )}>b = {b}</button>
</div>
);
}
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Қоидаи вобастагиҳо
Дар массив ҳамаи қиматҳоро аз компонент (props, state, функсияҳо), ки эффект мехонад, навиштан лозим аст. Агар эффект id-ро истифода барад, ва дар массив он набошад, эффект бо id-и «кӯҳна» кор мекунад — сарчашмаи аз ҳама маъмули хатоҳо. Муҳаррири хуб (ва ЗС) инро бо қоидаи react-hooks/exhaustive-deps мегӯяд; онро хомӯш накунед, балки кодро ислоҳ намоед.
Хатои маъмул: давраи беохир
Эффект бе массив, ки ҳолатро тағйир медиҳад, рендери навро оғоз мекунад, он — эффекти навро, ва ҳамин тавр то беохир. Браузер овезон мешавад ё React хатои «Too many re-renders»-ро мепартояд. Ин кодро дар лоиҳаи кории худ оғоз накунед.
Ин тавр кардан мумкин нест: давраи беохир
function Counter () {
const [n, setN] = useState (0 );
useEffect (() => {
setN (n + 1 ); // ✖ массиви вобастагиҳо нест: рендер → эффект → setN → рендер → ...
});
return <p>{n}</p>;
}
Муфассал хонед: learn.javascript.ru — Closure · react.dev — useEffect · react.dev — Synchronizing with Effects
Амалиёт: мустаҳкам мекунем
Дар ҳар вазифа «истифодабарандаи виртуалӣ» (useScript) худаш ҳолатро аз рӯи таймер тағйир медиҳад — ин тавр натиҷа дар консол ҳамеша якхела аст ва худкор санҷида мешавад. Блоки useScript ва ҳар чизеро, ки «стенд» нишон шудааст, тағйир надиҳед.
ВАЗИФАИ 1.1 Саҳифа кушода шуд осон
Эффектеро ба итмом расонед, ки Страница открыта-ро як маротиба — пас аз рендери аввал — чоп мекунад, на пас аз ҳар кадом. Аввал пешбинӣ кунед, ки сатрҳо чанд маротиба ва бо кадом тартиб пайдо мешаванд, баъд оғоз намоед.
Вазифаи 1.1 · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx
import { useEffect, useState } from "react" ;
export default function App () {
const [visits, setVisits] = useState (0 );
// стенд: пас аз 50 мс ҳисобкунак тағйир меёбад (гӯё истифодабаранда баргашт)
useEffect (() => {
const id = setTimeout (() => setVisits (1 ), 50 );
return () => clearTimeout (id);
}, []);
// TODO: useEffect-ро илова кунед, ки ЯК маротиба пас аз рендери аввал
// ба консол "Страница открыта"-ро чоп мекунад
console.log ("рендер" , visits);
return <p>Визитов: {visits}</p>;
}
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Натиҷаи интизоршаванда рендер 0
Страница открыта
рендер 1
Ишора 1 Эффект бо массиви холии вобастагиҳои [] танҳо пас аз рендери аввал иҷро мешавад.
Ишора 2 useEffect(() => { console.log("Страница открыта"); }, []); Рендери дуюм аз ҳисоби стенд рӯй медиҳад, аммо эффект бо [] ба он аллакай вокуниш нишон намедиҳад.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 1.2 Танҳо ҳисобро нигоҳ медорем миёна
Стенд ҳисобро, баъд мавзӯъро, боз ҳисобро тағйир медиҳад. Эффектеро нависед, ки сохраняем счёт: N-ро ҳангоми ҳар тағйири ҳисоб (аз ҷумла намоиши аввал) чоп мекунад, аммо ба иваз шудани мавзӯъ вокуниш нишон намедиҳад.
Вазифаи 1.2 · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx
import { useEffect, useState } from "react" ;
// стенд: «истифодабарандаи виртуалӣ» қадамҳоро аз рӯи таймер иҷро мекунад
function useScript (steps) {
useEffect (() => {
const ids = steps.map (([ms, fn]) => setTimeout (fn, ms));
return () => ids.forEach (clearTimeout);
}, []);
}
export default function App () {
const [count, setCount] = useState (0 );
const [theme, setTheme] = useState ("light" );
// стенд: ҳисоб +1, баъд иваз шудани мавзӯъ, баъд ҳисоб боз +1
useScript ([
[40 , () => setCount (1 )],
[80 , () => setTheme ("dark" )],
[120 , () => setCount (2 )],
]);
// TODO: эффекте, ки "сохраняем счёт: N"-ро чоп мекунад
// ва ТАНҲО вақте кор мекунад, ки count тағйир ёфт (иваз шудани мавзӯъ ба он дахл надорад)
return <p className={theme}>Счёт: {count}</p>;
}
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Натиҷаи интизоршаванда сохраняем счёт: 0
сохраняем счёт: 1
сохраняем счёт: 2
Ишора 1 Барои он ки эффект танҳо аз паси ҳисоб равад, маҳз ҳамин тағйирёбандаро ба массиви вобастагиҳо гузоред.
Ишора 2 useEffect(() => { console.log("сохраняем счёт:", count); }, [count]);
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 1.3 Сарлавҳаи ҷадвал осон
Компонент номеро мегирад, ки тағйир меёбад. Эффект нависед: ҳангоми ҳар иваз шудани ном он document.title-ро мегузорад ва онро ба консол чоп мекунад. Тағйири document.title — таъсири ҷонибии классикӣ аст: он аз ҳудуди JSX берун меравад.
Вазифаи 1.3 · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx
import { useEffect, useState } from "react" ;
function useScript (steps) {
useEffect (() => {
const ids = steps.map (([ms, fn]) => setTimeout (fn, ms));
return () => ids.forEach (clearTimeout);
}, []);
}
export default function App () {
const [name, setName] = useState ("Мадина" );
useScript ([[50 , () => setName ("Фарход" )]]); // стенд: ном пас аз 50 мс тағйир меёбад
// TODO: эффекте, ки ҳангоми ҳар иваз шудани name
// 1) document.title = "Привет, " + name мегузорад
// 2) console.log("заголовок:", document.title)-ро чоп мекунад
return <h1>Привет, {name}!</h1>;
}
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Натиҷаи интизоршаванда заголовок: Привет, Мадина
заголовок: Привет, Фарход
Ишора 1 Эффект бояд ҳангоми иваз шудани name аз нав оғоз шавад — пас name дар массиви вобастагиҳо аст.
Ишора 2 document.title = "Привет, " + name;, ва бо сатри навбатӣ console.log("заголовок:", document.title);
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
02 Cleanup: ба паси худ тозакорӣ кардан лозим аст
Эффект метавонад функсияро баргардонад — онро cleanup («тозакорӣ») меноманд. React онро дар ду ҳолат даъват мекунад: пеш аз он ки эффектро аз нав оғоз кунад (ҳангоми иваз шудани вобастагиҳо) ва вақте ки компонент аз экран нопадид мешавад.
Қолаби эффект бо cleanup
useEffect (() => {
// 1) «фаъол мекунем»: таймер, обуна, дархост
const id = setInterval (tick, 1000 );
// 2) «хомӯшкунанда»-ро бармегардонем
return () => clearInterval (id);
}, []);
Монанд аз ҳаёт
Шумо бо маршрутка омадед ва дар он радиоро бо садои пурра фаъол кардед. Агар бе хомӯш кардан фуромада равед, радио барои салони холӣ садо медиҳад ва ба мусофирони навбатӣ халал мерасонад. Cleanup — ин «радиоро хомӯш кардан ҳангоми баромадан» аст. Таймер бе cleanup ҳамин тавр дар компонент, ки аллакай нест, тиқ-тиқ карданро давом медиҳад.
Тартиб ҳангоми иваз шудани вобастагиҳо
Эффект бо room = "Общий" оғоз шуд: пайваст шудем.
room ба "Группа JS" иваз шуд: React аввал cleanup-и эффекти кӯҳна -ро даъват мекунад (аз «Общий» ҷудо шудем)…
…ва танҳо баъд эффектро бо қимати нав оғоз мекунад (ба «Группа JS» пайваст шудем).
Компонентро аз экран бардоштанд: cleanup-и охирин — ҷудо шудем.
StrictMode: барои чӣ React эффектро ду маротиба оғоз мекунад
Вақте ки Шумо лоиҳаро дар Vite ё Next.js эҷод мекунед, компонентҳо одатан дар <StrictMode> печонида шудаанд. Дар реҷаи таҳия он қасдан «репетитсия» мекунад: эффектро оғоз мекунад, фавран cleanup-ро даъват мекунад ва эффектро боз як маротиба оғоз мекунад. Ин тавр React месанҷад, ки эффекти Шумо «хомӯш шуданро» медонад ва ахлот намегузорад. Дар барпоии тайёр (production) ин такрор нест.
Компонент дар StrictMode (реҷаи таҳия)
function Clock () {
const [seconds, setSeconds] = useState (0 );
useEffect (() => {
console.log ("эффект: запускаем таймер" );
const id = setInterval (() => setSeconds ((s) => s + 1 ), 1000 );
return () => {
console.log ("cleanup: останавливаем таймер" );
clearInterval (id);
};
}, []);
return <p>Прошло секунд: {seconds}</p>;
}
Шумо дар консол ҳангоми таҳия бо StrictMode чиро мебинед
эффект: запускаем таймер
cleanup: останавливаем таймер
эффект: запускаем таймер
Ба «оғози дукарата» чӣ тавр муносибат кардан лозим аст
Ин хато нест ва «React вайрон нашудааст». Агар пас аз оғози дукарата барнома чунон ки лозим аст, кор кунад — cleanup дуруст навишта шудааст. Агар дархост ду маротиба меравад ё таймерҳо тез мешаванд — Шумо cleanup-ро фаромӯш кардед. Равзанаҳои таълимии ин саҳифа дар реҷаи production кор мекунанд, бинобар ин такрор дар онҳо намоён нест; худатон санҷед, вақте ки лоиҳаро дар Vite эҷод мекунед.
Хатои маъмул: тоза кардани таймерро фаромӯш кардед
Бе cleanup интервал пас аз рафтани компонент зинда мемонад: рехтани хотира ва навкунии ҳолати компоненти ғайримавҷуд.
Ин тавр кардан мумкин нест: cleanup нест
useEffect (() => {
setInterval (() => console.log ("тик" ), 1000 ); // ✖ ҳеҷ кас ин таймерро қатъ намекунад
}, []);
Муфассал хонед: learn.javascript.ru — setTimeout ва setInterval · react.dev — You Might Not Need an Effect
Амалиёт: мустаҳкам мекунем
ВАЗИФАИ 2.1 Таймерро қатъ кунед осон
Компоненти Ticker ҳар 100 мс «тик N» менависад. Стенд онро пас аз 350 мс аз экран мебардорад. Cleanup-ро ба итмом расонед: он таймерро қатъ мекунад ва таймер остановлен-ро чоп мекунад. Агар cleanup-ро фаромӯш кунед, тикҳо қатъ намешаванд — коди оғозиро оғоз кунед ва боварӣ ҳосил намоед.
Вазифаи 2.1 · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx
import { useEffect, useState } from "react" ;
function useScript (steps) {
useEffect (() => {
const ids = steps.map (([ms, fn]) => setTimeout (fn, ms));
return () => ids.forEach (clearTimeout);
}, []);
}
function Ticker () {
useEffect (() => {
let n = 0 ;
const id = setInterval (() => {
n++;
console.log ("тик" , n);
}, 100 );
// TODO: функсияи тозакуниро баргардонед: он таймерро қатъ мекунад (clearInterval)
// ва "таймер остановлен"-ро чоп мекунад
}, []);
return <p>Идёт отсчёт…</p>;
}
export default function App () {
const [show, setShow] = useState (true );
useScript ([[350 , () => setShow (false )]]); // стенд: пас аз 350 мс компонентро пинҳон мекунанд
return show ? <Ticker /> : <p>Скрыто</p>;
}
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Натиҷаи интизоршаванда тик 1
тик 2
тик 3
таймер остановлен
Ишора 1 Дар охири эффект return () => { ... } лозим аст. Шиносаи таймери id аллакай назди Шумо аст.
Ишора 2 return () => { clearInterval(id); console.log("таймер остановлен"); };
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 2.2 Ҳуҷраҳои чат миёна
Эффекти компоненти Chat-ро нависед: ҳангоми намоиши ҳуҷра connect(room)-ро даъват кунед, ва ҳангоми иваз шудани ҳуҷра ё пӯшидани чат — disconnect(room)-ро барои ҳамон ҳуҷра, ки ба он пайваст шуда будед. Ба тартиби сатрҳо диққат диҳед.
Вазифаи 2.2 · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx
import { useEffect, useState } from "react" ;
function useScript (steps) {
useEffect (() => {
const ids = steps.map (([ms, fn]) => setTimeout (fn, ms));
return () => ids.forEach (clearTimeout);
}, []);
}
// «пайваст шудан ба ҳуҷраи чат»
function connect (room) { console.log ("подключились:" , room); }
function disconnect (room) { console.log ("отключились:" , room); }
function Chat ({ room }) {
// TODO: ба ҳуҷра пайваст шавед, ва ҳангоми иваз шудани ҳуҷра ва ҳангоми пӯшидани чат — ҷудо шавед
return <p>Комната: {room}</p>;
}
export default function App () {
const [room, setRoom] = useState ("Общий" );
const [open, setOpen] = useState (true );
// стенд: пас аз 50 мс — ҳуҷраи дигар, пас аз 100 мс — чатро мепӯшанд
useScript ([
[50 , () => setRoom ("Группа JS" )],
[100 , () => setOpen (false )],
]);
return open ? <Chat room={room} /> : <p>Чат закрыт</p>;
}
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Натиҷаи интизоршаванда подключились: Общий
отключились: Общий
подключились: Группа JS
отключились: Группа JS
Ишора 1 Эффект аз room вобаста аст: он бояд ҳангоми иваз шудани он аз нав оғоз шавад. Ва cleanup он қимати room-ро «ба ёд дорад», ки бо он эффекташ оғоз шуда буд.
Ишора 2 useEffect(() => { connect(room); return () => disconnect(room); }, [room]);
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
03 Боркунии маълумот: чор ҳолат
Кори аз ҳама маъмул барои useEffect — гирифтани маълумот аз сервер ҳангоми кушодани экран. Дархост — таъсири ҷонибӣ аст, бинобар ин ҷояш дар бадани компонент нест. Ва азбаски ҷавоб фавран намеояд, экран дар чор ҳолат зиндагӣ мекунад, ва ҳар кадомро ба истифодабаранда нишон додан лозим аст (Шумо онҳоро дар дарси 16 дида будед):
Ҳолат Истифодабаранда чиро мебинад Чӣ тавр мефаҳмем loading «Боршавӣ…», скелетон ё спиннер дархост рафт, ҷавоб ҳанӯз нест error паёми фаҳмо ва тугмаи «Такрор» шабака афтод ё response.ok === false empty «Чизе ёфт нашуд» ҷавоб омад, аммо массив холӣ аст success рӯйхат ё кортҳо ҷавоб омад, маълумот ҳаст
Монанд аз ҳаёт
Шумо дар барнома таксӣ фармудед. «Мошин меҷӯем» — loading. «Мошин нест, баъдтар кӯшиш кунед» — error. «Дар минтақаи Шумо тарифҳои дастрас нестанд» — empty. «Ронанда Фарход пас аз 4 дақиқа меояд» — success. Агар барнома ба ҷои ҳар яке аз ин паёмҳо экрани холии сафед нишон диҳад, истифодабаранда мепиндорад, ки он вайрон шудааст.
Скелети компонент
Ҳолатҳои экран якчандто ҳастанд — онҳоро дар useState нигоҳ медорем. «Холӣ»-ро алоҳида нигоҳ доштан лозим нест: ин муваффақият бо массиви холӣ аст.
Қолаб: боркунии маълумот дар useEffect
function StudentList () {
const [status, setStatus] = useState ("loading" ); // loading | error | success
const [students, setStudents] = useState ([]);
const [error, setError] = useState ("" );
useEffect (() => {
fetch ("/api/students" )
.then ((response) => {
if (!response.ok) throw new Error ("HTTP " + response.status); // 404 ва 500 — ҳам хато аст
return response.json ();
})
.then ((data) => {
setStudents (data);
setStatus ("success" );
})
.catch ((err) => {
setError (err.message);
setStatus ("error" );
});
}, []);
if (status === "loading" ) return <p>Загрузка…</p>;
if (status === "error" ) return <p>Ошибка: {error}</p>;
if (students.length === 0 ) return <p>Ничего не найдено</p>;
return (
<ul>
{students.map ((s) => <li key={s.id}>{s.name}</li>)}
</ul>
);
}
Ба тартиби if диққат диҳед: аввал бозгаштҳои барвақт барои боршавӣ, хато ва рӯйхати холӣ, ва дар охир — «роҳи хушбахт» бо маълумот. Ин тавр компонент аз боло ба поён, мисли чек-лист хонда мешавад.
Хатои маъмул: async бевосита дар useEffect
useEffect(async () => { ... }) навиштан мумкин нест: функсияи async ҳамеша promise бармегардонад, ва React аз эффект ё чизе, ё функсияи cleanup интизор аст. Агар await лозим бошад — функсияи async-ро дар дохили эффект эълон кунед ва онро даъват намоед (мисли вазифаи 3.1), ё .then-ро истифода баред, мисли дар қолаби боло.
Ин тавр кардан мумкин нест
useEffect (async () => { // ✖ эффект promise-ро бармегардонад, на cleanup
const response = await fetch ("/api/students" );
setStudents (await response.json ());
}, []);
Мисоли зинда бо API-и воқеӣ
Ин барнома ба jsonplaceholder.typicode.com мераваду. Тугмаи «Сломать адрес» дархостро ба саҳифаи ғайримавҷуд равона мекунад — Шумо ҳолати хаторо мебинед; «Повторить» эффектро аз нав оғоз мекунад (рақами attempt дар вобастагиҳо аст). Санҷиши худкор инҷо нест — танҳо омӯхта бинед.
Дархости зинда: истифодабарандагон · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx
import { useEffect, useState } from "react" ;
const GOOD = "https://jsonplaceholder.typicode.com/users?_limit=5" ;
const BAD = "https://jsonplaceholder.typicode.com/nothing-here" ; // 404 бармегардонад
export default function App () {
const [url, setUrl] = useState (GOOD);
const [attempt, setAttempt] = useState (0 ); // «Повторить» рақамро зиёд мекунад ва эффектро аз нав оғоз мекунад
const [status, setStatus] = useState ("loading" );
const [users, setUsers] = useState ([]);
const [error, setError] = useState ("" );
useEffect (() => {
const controller = new AbortController ();
setStatus ("loading" );
fetch (url, { signal: controller.signal })
.then ((response) => {
if (!response.ok) throw new Error ("HTTP " + response.status);
return response.json ();
})
.then ((data) => {
setUsers (data);
setStatus ("success" );
})
.catch ((err) => {
if (err.name === "AbortError" ) return ; // инро мо худамон бекор кардем — хато нест
setError (err.message);
setStatus ("error" );
});
return () => controller.abort ();
}, [url, attempt]);
return (
<div>
<button onClick={() => setUrl (url === GOOD ? BAD : GOOD)}>
{url === GOOD ? "Сломать адрес" : "Починить адрес" }
</button>{" " }
<button onClick={() => setAttempt (attempt + 1 )}>Повторить</button>
{status === "loading" && <p>Загрузка…</p>}
{status === "error" && <p style={{ color: "#c0392b" }}>Не получилось: {error}</p>}
{status === "success" && users.length === 0 && <p>Список пуст</p>}
{status === "success" && (
<ul>
{users.map ((u) => (
<li key={u.id}>{u.name} ({u.address.city})</li>
))}
</ul>
)}
</div>
);
}
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Муфассал хонед: learn.javascript.ru — Fetch · react.dev — Fetching data in Effects
Амалиёт: мустаҳкам мекунем
ВАЗИФАИ 3.1 Дархости аввал дар эффект осон
Эффектро ба итмом расонед: як маротиба fakeFetch("/api/students")-ро дархост кунед, JSON-ро бихонед ва маълумотро ба ҳолат гузоред. Сатр дар консол нишон медиҳад, ки ҳоло кадом экран кашида шудааст.
Вазифаи 3.1 · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx
import { useEffect, useState } from "react" ;
const STUDENTS = [
{ id: 1 , name: "Мадина" },
{ id: 2 , name: "Фарход" },
{ id: 3 , name: "Нилуфар" },
];
// стенд: «сервер» пас аз 100 мс ҷавоб медиҳад, мисли fetch-и воқеӣ
function fakeFetch (url) {
return new Promise ((resolve) => {
setTimeout (() => resolve ({ ok: true , status: 200 , json: async () => STUDENTS }), 100 );
});
}
export default function App () {
const [status, setStatus] = useState ("loading" );
const [students, setStudents] = useState ([]);
console.log ("экран:" , status === "loading" ? "загрузка" : `список (${students.length})` );
// TODO: useEffect-е, ки як маротиба
// 1) fakeFetch("/api/students")-ро даъват мекунад
// 2) response.json()-ро мехонад
// 3) маълумотро ба students мегузорад ва status "success"-ро таъин мекунад
if (status === "loading" ) return <p>Загрузка…</p>;
return (
<ul>
{students.map ((s) => (
<li key={s.id}>{s.name}</li>
))}
</ul>
);
}
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Натиҷаи интизоршаванда экран: загрузка
экран: список (3)
Ишора 1 Эффект бо []. Дар дохил async function load()-ро эълон кунед ва фавран даъват намоед.
Ишора 2 Дар load: const response = await fakeFetch(...), const data = await response.json(), баъд setStudents(data) ва setStatus("success").
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 3.2 Ҳамаи чор ҳолат миёна
Стенд навбат ба навбат се «суроға» мехоҳад: рӯйхат, рӯйхати холӣ ва сервери вайроншуда (ҳолати 500). Боркуниро бо санҷиши response.ok ва чор шохаи кашиданро бо console.log-и лозимӣ нависед. Компонент барои ҳар суроға аз нав эҷод мешавад (key масъул аст), бинобар ин ҳолат ҳар дафъа аз «боршавӣ» оғоз мешавад.
Вазифаи 3.2 · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx
import { useEffect, useState } from "react" ;
function useScript (steps) {
useEffect (() => {
const ids = steps.map (([ms, fn]) => setTimeout (fn, ms));
return () => ids.forEach (clearTimeout);
}, []);
}
const STUDENTS = [
{ id: 1 , name: "Мадина" },
{ id: 2 , name: "Фарход" },
{ id: 3 , name: "Нилуфар" },
];
// стенд: се «суроға» — рӯйхат, рӯйхати холӣ ва сервери вайроншуда (500)
function fakeFetch (url) {
return new Promise ((resolve) => {
setTimeout (() => {
if (url === "/api/students" ) resolve ({ ok: true , status: 200 , json: async () => STUDENTS });
else if (url === "/api/empty" ) resolve ({ ok: true , status: 200 , json: async () => [] });
else resolve ({ ok: false , status: 500 , json: async () => ({}) });
}, 100 );
});
}
function StudentList ({ url }) {
const [status, setStatus] = useState ("loading" );
const [items, setItems] = useState ([]);
const [error, setError] = useState ("" );
// TODO 1: useEffect-е, ки url-ро бор мекунад ва status / items / error-ро пеш мебарад.
// Санҷидани response.ok ва нишон додани url дар вобастагиҳоро фаромӯш накунед.
// TODO 2: чор шохаи кашидан. Дар ҳар кадом — console.log-и худӣ:
// боршавӣ → "экран: загрузка"
// хато → "экран: ошибка —", error
// холӣ → "экран: пусто"
// рӯйхат → "экран: список (N)"
return null ;
}
export default function App () {
const [url, setUrl] = useState ("/api/students" );
// стенд: суроға ду маротиба иваз мешавад. key компонентро маҷбур мекунад, ки аз саҳифаи тоза оғоз кунад
useScript ([
[400 , () => setUrl ("/api/empty" )],
[800 , () => setUrl ("/api/broken" )],
]);
return <StudentList key={url} url={url} />;
}
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Натиҷаи интизоршаванда экран: загрузка
экран: список (3)
экран: загрузка
экран: пусто
экран: загрузка
экран: ошибка — HTTP 500
Ишора 1 Санҷиши ҳолат: if (!response.ok) throw new Error("HTTP " + response.status); — истисно ба .catch меафтад, ки дар он Шумо err.message-ро нигоҳ медоред ва status = "error"-ро таъин мекунед.
Ишора 2 Шохаҳо бо ин тартиб мераванд: loading, error, items.length === 0, баъд рӯйхат. Дар ҳар кадом пеш аз return — console.log-и худӣ. Вобастагии эффект — [url].
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 3.3 Хаторо ёбед: 404 — ин «муваффақият» аст? миёна
Сервер бо ҳолати 404 ҷавоб дод, аммо компонент чунон рафтор мекунад, ки гӯё ҳама чиз хуб аст, ва ҳангоми кашидан меафтад. Коди оғозиро оғоз кунед ва ба хато дар консол нигаред, баъд танҳо эффектро ислоҳ кунед: ҷавоб бо ok === false бояд ба экрани хато оварад.
Вазифаи 3.3 · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx
import { useEffect, useState } from "react" ;
// стенд: сервер бо «404 Ёфт нашуд» ҷавоб медиҳад, аммо fetch инро хато ҳисоб НАМЕКУНАД
function fakeFetch (url) {
return new Promise ((resolve) => {
setTimeout (() => resolve ({ ok: false , status: 404 , json: async () => ({ message: "Not found" }) }), 100 );
});
}
export default function App () {
const [courses, setCourses] = useState (null );
const [error, setError] = useState (null );
useEffect (() => {
fakeFetch ("/api/courses" )
.then ((response) => response.json ())
.then ((data) => setCourses (data))
.catch ((err) => setError (err.message));
}, []);
if (error) {
console.log ("экран: ошибка —" , error);
return <p>{error}</p>;
}
if (!courses) {
console.log ("экран: загрузка" );
return <p>Загрузка…</p>;
}
console.log ("экран: курсов" , courses.length);
return (
<ul>
{courses.map ((c) => (
<li key={c.id}>{c.title}</li>
))}
</ul>
);
}
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Натиҷаи интизоршаванда экран: загрузка
экран: ошибка — HTTP 404
Ишора 1 fetch promise-ро танҳо ҳангоми хатои шабака рад мекунад. Ҷавобҳои 404 ва 500 барои он — «ҷавобро бомуваффақият гирифтем» мебошанд.
Ишора 2 Дар .then-и аввал пеш аз return response.json() санҷиши if (!response.ok) throw new Error("HTTP " + response.status);-ро илова кунед
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
04 Мусобиқаи дархостҳо ва AbortController
Экрани профилро бо тугмаҳои «Мадина» ва «Фарход» тасаввур кунед. Шумо «Мадина»-ро пахш кардед — дархост рафт, ва он суст аст. Интизор нашуда, «Фарход»-ро пахш кардед — дархости дуюм тез аст ва аввал баргашт. Экран Фарходро нишон дод. Аммо баъд ниҳоят ҷавоби дархости аввал меояд ва экранро аз нав менависад: дар сарлавҳа «Фарход», ва маълумот — аз они Мадина. Ин мусобиқаи дархостҳо (race condition) номида мешавад, ва он дар сайтҳои воқеӣ пайваста рух медиҳад.
Монанд аз ҳаёт
Шумо дар як чойхона палав фармудед, аммо фавран фикратонро иваз карда, дар дигаре қурутоб фармудед. Қурутобро зуд оварданд, шумо хӯрданро сар кардед — ва ногаҳон курйер палавро меорад, ки Шумо онро бекор карда будед. Рафтори дуруст — ба чойхонаи аввал занг задан ва фармоишро бекор кардан аст. Барои дархостҳо бекоркунӣ — ин AbortController аст.
AbortController дар ду сатр
Шумо контроллер эҷод мекунед, signal-и онро ба fetch медиҳед, ва вақте ки дархост дигар лозим нест, controller.abort()-ро даъват мекунед. Promise-и fetch он гоҳ бо хатои AbortError рад карда мешавад.
AbortController бе React · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const controller = new AbortController ();
fetch ("https://jsonplaceholder.typicode.com/users/1" , { signal: controller.signal })
.then ((r) => r.json ())
.then ((user) => console.log ("получили" , user.name))
.catch ((err) => console.log ("ошибка:" , err.name));
controller.abort (); // фавран фикр иваз кардем
console.log ("aborted:" , controller.signal.aborted);
Дар эффект чӣ тавр менамояд
Cleanup-и эффект — ҷои беҳтарин барои abort() аст: React онро пеш аз такрори оғози эффект ва ҳангоми рафтани компонент даъват мекунад.
Қолаб: дархост бо бекоркунӣ
useEffect (() => {
const controller = new AbortController ();
fetch (`/api/users/${id}` , { signal: controller.signal })
.then ((r) => {
if (!r.ok) throw new Error ("HTTP " + r.status);
return r.json ();
})
.then ((user) => setUser (user))
.catch ((err) => {
if (err.name === "AbortError" ) return ; // мо худамон бекор кардем — барои истифодабаранда ин хато нест
setError (err.message);
});
return () => controller.abort (); // ҳангоми иваз шудани id ё рафтан аз саҳифа бекор мекунем
}, [id]);
Варианти эҳтиётӣ: парчами ignore
Агар бекор кардан чизе нест (масалан, китобхона signal-ро қабул намекунад), парчамро истифода баред: let ignore = false; дар эффект, if (!ignore) setUser(user) дар коркардкунанда ва return () => { ignore = true; } дар cleanup. Дархост бекор намешавад, аммо натиҷаи он нодида гирифта мешавад. Бекоркунӣ беҳтар аст: он боз траффикро ҳам сарфа мекунад.
Хатои маъмул: AbortError-ро ба истифодабаранда нишон медиҳем
Агар дар .catch танҳо setError(err.message) кунед, ҳангоми ҳар иваз шудан истифодабаранда барои як лаҳза «The user aborted a request»-ро мебинад. err.name === "AbortError"-ро санҷед ва хомӯшона бароед.
Муфассал хонед: learn.javascript.ru — Fetch: қатъ кардани дархост · MDN — AbortController
Амалиёт: мустаҳкам мекунем
ВАЗИФАИ 4.1 Хаторо ёбед: ҷавоби бегона дар экран душвор
Профили 1 «сервер» дар 300 мс медиҳад, профили 2 — дар 50 мс. Истифодабаранда аз 1 ба 2 пас аз 20 мс гузашт. Коди оғозиро оғоз кунед: дар консол сатри иловагии id 2 → Мадина пайдо мешавад — дар экран профили 2, ва маълумоти профили 1. Эффектро ислоҳ кунед (бекор кардани дархост ё парчами ignore), то танҳо се сатр монад. Агар бекоркуниро интихоб кардед, дар бораи AbortError фаромӯш накунед.
Вазифаи 4.1 · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx
import { useEffect, useState } from "react" ;
function useScript (steps) {
useEffect (() => {
const ids = steps.map (([ms, fn]) => setTimeout (fn, ms));
return () => ids.forEach (clearTimeout);
}, []);
}
// --- стенд: профили 1 «сервер» дер медиҳад (300 мс), профили 2 — зуд (50 мс) ---
const NAMES = { 1 : "Мадина" , 2 : "Фарход" };
const DELAY = { 1 : 300 , 2 : 50 };
function fakeFetch (url, { signal } = {}) {
const id = Number (url.split ("/" ).pop ());
return new Promise ((resolve, reject) => {
const t = setTimeout (
() => resolve ({ ok: true , status: 200 , json: async () => ({ id, name: NAMES[id] }) }),
DELAY[id]
);
signal?. addEventListener ("abort" , () => {
clearTimeout (t);
reject (new DOMException ("Aborted" , "AbortError" ));
});
});
}
// --- компонент бо хато ---
function Profile ({ id }) {
const [user, setUser] = useState (null );
console.log ("id" , id, "→" , user ? user.name : "нет данных" );
useEffect (() => {
fakeFetch (`/api/users/${id}` )
.then ((r) => r.json ())
.then ((u) => setUser (u));
}, [id]);
return <p>{user ? user.name : "Загрузка…" }</p>;
}
export default function App () {
const [id, setId] = useState (1 );
useScript ([[20 , () => setId (2 )]]); // стенд: истифодабаранда зуд аз 1 ба 2 гузашт
return <Profile id={id} />;
}
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Натиҷаи интизоршаванда id 1 → нет данных
id 2 → нет данных
id 2 → Фарход
Ишора 1 Ҷавоби кӯҳнаро ё бекор кардан лозим аст, ё нодида гирифтан, вақте ки id аллакай иваз шудааст. Ҳам яке ва ҳам дигаре дар cleanup-и эффект иҷро мешавад.
Ишора 2 Бо бекоркунӣ: const controller = new AbortController();, { signal: controller.signal }-ро ҳамчун аргументи дуюм ба fakeFetch додан, return () => controller.abort();, ва дар .catch AbortError-ро нодида гирифтан.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 4.2 Бекоркунӣ дар JS-и тоза осон
Амал 500 мс интизор мешавад, аммо истифодабаранда пас аз 100 мс фикрашро иваз кард. Бекоркуниро ба итмом расонед. Тартиби сатрҳоро пешбинӣ кунед: чаро «после отмены» пештар аз «ошибка» чоп мешавад?
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
// стенд: ms миллисония интизор мешавад; signal-ро мефаҳмад, мисли fetch-и воқеӣ
function wait (ms, signal) {
return new Promise ((resolve, reject) => {
const t = setTimeout (() => resolve ("готово" ), ms);
signal.addEventListener ("abort" , () => {
clearTimeout (t);
reject (new DOMException ("Отменено" , "AbortError" ));
});
});
}
const controller = new AbortController ();
wait (500 , controller.signal)
.then ((r) => console.log (r))
.catch ((e) => console.log ("ошибка:" , e.name));
console.log ("до отмены:" , controller.signal.aborted);
// TODO: пас аз 100 мс controller.abort()-ро даъват кунед
// ва фавран пас аз он "после отмены:", controller.signal.aborted-ро чоп кунед
Натиҷаи интизоршаванда до отмены: false
после отмены: true
ошибка: AbortError
Ишора 1 setTimeout барои 100 мс лозим аст, ки дар дохили он controller.abort() даъват мешавад.
Ишора 2 abort() фавран иҷро мешавад, ва .catch — каме дертар, дар навбати микровазифаҳо (дарси 13). Бинобар ин console.log-и пас аз abort() аввал мерасад.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 4.3 Аз саҳифа рафтем — дархостро бекор кардем миёна
Компоненти Report ҳисоботро дархост мекунад, аммо истифодабаранда пас аз 50 мс аз саҳифа меравад. Ҳоло ҳисобот ба ҳар ҳол «ба ҳеҷ ҷо» меояд. Бекоркуниро ба итмом расонед, то шохаи AbortError кор кунад.
Вазифаи 4.3 · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx
import { useEffect, useState } from "react" ;
function useScript (steps) {
useEffect (() => {
const ids = steps.map (([ms, fn]) => setTimeout (fn, ms));
return () => ids.forEach (clearTimeout);
}, []);
}
// стенд: ҳисобот 200 мс «ҳисоб карда мешавад»; fakeFetch signal-ро мефаҳмад, мисли fetch-и воқеӣ
function fakeFetch (url, { signal } = {}) {
return new Promise ((resolve, reject) => {
const t = setTimeout (() => resolve ({ ok: true , status: 200 , json: async () => ({ rows: 42 }) }), 200 );
signal?. addEventListener ("abort" , () => {
clearTimeout (t);
reject (new DOMException ("Aborted" , "AbortError" ));
});
});
}
function Report () {
useEffect (() => {
console.log ("запрос начат" );
// TODO: AbortController эҷод кунед, signal-ро ба fakeFetch диҳед
// ва cleanup-ро баргардонед, ки дархостро бекор мекунад
fakeFetch ("/api/report" )
.then ((r) => r.json ())
.then ((data) => console.log ("отчёт получен, строк:" , data.rows))
.catch ((err) => {
if (err.name === "AbortError" ) console.log ("запрос отменён" );
else console.log ("ошибка:" , err.message);
});
}, []);
return <p>Формируем отчёт…</p>;
}
export default function App () {
const [show, setShow] = useState (true );
useScript ([[50 , () => setShow (false )]]); // стенд: пас аз 50 мс истифодабаранда аз саҳифа рафт
return show ? <Report /> : <p>Страница закрыта</p>;
}
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Натиҷаи интизоршаванда запрос начат
запрос отменён
Ишора 1 Контроллер дар дохили эффект эҷод мешавад; fakeFetch { signal }-ро ҳамчун аргументи дуюм мегирад.
Ишора 2 const controller = new AbortController(); → fakeFetch("/api/report", { signal: controller.signal }) → дар охири эффект return () => controller.abort();
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
05 Ҷустуҷӯ, debounce ва филтркунӣ
Филтркунӣ: на ҳолат лозим аст ва на эффект
Фарз кунед, ки Шумо рӯйхат ва сатри ҷустуҷӯ доред. Навомӯзон аксар вақт барои «рӯйхати филтршуда» useState-и дуюмро ташкил медиҳанд ва онро дар эффект нав мекунанд. Ин зиёдатӣ аст: рӯйхати филтршуда пурра аз ду қимат ҳисоб карда мешавад — рӯйхати пурра ва сатри ҷустуҷӯ. Чунин маълумот ҳосилавӣ номида мешавад, ва ҳисоб кардани онро бевосита ҳангоми рендер бояд кард.
Маълумоти ҳосилавӣ: ҳангоми рендер ҳисоб мекунем
const [query, setQuery] = useState ("" );
// ✔ дар парвоз ҳисоб мекунем, ҳеҷ useEffect ва useState-и дуюм нест
const visible = students.filter ((s) =>
s.name.toLowerCase ().includes (query.trim ().toLowerCase ())
);
Монанд аз ҳаёт
Менюи рӯи девори чойхона як аст. Вақте ки меҳмон мегӯяд «ба ман чизе бе гӯшт», пешхизмат менюро аз нав наменависад ва дуюмро овезон намекунад — ӯ танҳо дар зеҳн таомҳои гӯштиро мегузаронад. Рӯйхати филтршуда — «нигоҳ ба меню» аст, на менюи нав.
Ҷустуҷӯ тавассути сервер ва debounce барои чӣ лозим аст
Агар дар рӯйхати ҳазорон сабт ҷустуҷӯ кунед, филтр кардан дар клиент аллакай мумкин нест — дархост ба сервер лозим аст: /users/search?q=плов. Аммо агар барои ҳар клавишаи пахшшуда дархост фиристед, то даме ки истифодабаранда «плов»-ро чоп мекунад, чор дархост меравад: п, пл, пло, плов. Се тоаш ба ҳеҷ кас лозим нестанд, ва онҳо метавонанд бо тартиби омехта баргарданд.
Debounce («ларзиш») — усул аст: 300–500 мс интизор шудан, то истифодабаранда чоп карданро бас кунад , ва танҳо баъд ҷустуҷӯ кардан. Ҳар пахши нав таймерро аз нав мегузорад.
п · пл · пло · плов
⏸
поиск: плов
Чор пахш — як дархост
Аввал худи ядрои ғоя дар JS-и тоза — функсияи debounce, ки ҳама ҷо истифода мешавад, на танҳо дар React. Ва дар React ҳамин чиз ҳамчун ҳуки худӣ ташкил карда мешавад:
Ҳуки useDebounce: қимат «бо таъхир»
function useDebounce (value, delay) {
const [debounced, setDebounced] = useState (value);
useEffect (() => {
const id = setTimeout (() => setDebounced (value), delay);
return () => clearTimeout (id); // пахши нав таймери кӯҳнаро бекор мекунад
}, [value, delay]);
return debounced;
}
Ин мисоли зебои cleanup аст: ҳар тағйири value таймери тағйири гузаштаро мебардорад, ва то охир танҳо охиринаш зинда мемонад. Истифода: эффекти дархост на аз query (дар ҳар ҳарф тағйир меёбад), балки аз debounced вобаста аст.
Мисоли зинда: ҷустуҷӯ бо API-и воқеӣ
Номҳои англисиро чоп кунед (ma, ol, ja) ва аз паси ҳисобкунаки дархостҳо равед: то даме ки пай дар пай чоп мекунед, он намеафзояд. Дархости гузашта тавассути AbortController бекор мешавад.
Ҷустуҷӯ бо debounce (dummyjson.com) · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx
import { useEffect, useState } from "react" ;
function useDebounce (value, delay) {
const [debounced, setDebounced] = useState (value);
useEffect (() => {
const id = setTimeout (() => setDebounced (value), delay);
return () => clearTimeout (id);
}, [value, delay]);
return debounced;
}
export default function App () {
const [query, setQuery] = useState ("" );
const debounced = useDebounce (query, 400 );
const [status, setStatus] = useState ("idle" );
const [users, setUsers] = useState ([]);
const [requests, setRequests] = useState (0 );
useEffect (() => {
if (debounced.trim () === "" ) {
setUsers ([]);
setStatus ("idle" );
return ;
}
const controller = new AbortController ();
setStatus ("loading" );
setRequests ((n) => n + 1 );
fetch (`https://dummyjson.com/users/search?q=${encodeURIComponent(debounced)}&limit=5&select=firstName,lastName` , {
signal: controller.signal,
})
.then ((r) => {
if (!r.ok) throw new Error ("HTTP " + r.status);
return r.json ();
})
.then ((data) => {
setUsers (data.users);
setStatus ("success" );
})
.catch ((err) => {
if (err.name !== "AbortError" ) setStatus ("error" );
});
return () => controller.abort ();
}, [debounced]);
return (
<div>
<input
value={query}
onChange={(e) => setQuery (e.target.value)}
placeholder="Имя на английском: ma, ol, ja…"
/>
<p style={{ color: "#667" , fontSize: 14 }}>Запросов к серверу: {requests}</p>
{status === "idle" && <p>Начните печатать имя</p>}
{status === "loading" && <p>Ищем…</p>}
{status === "error" && <p style={{ color: "#c0392b" }}>Ошибка сети</p>}
{status === "success" && users.length === 0 && <p>Никого не нашли</p>}
{status === "success" && (
<ul>
{users.map ((u) => (
<li key={u.id}>{u.firstName} {u.lastName}</li>
))}
</ul>
)}
</div>
);
}
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Хатои маъмул: филтр дар эффект бо ҳолати зиёдатӣ
Нусхаи маълумот дар useState + useEffect барои ҳамоҳангсозӣ — ин рендери иловагӣ ҳангоми ҳар тағйирот ва хатари нишон додани рӯйхати кӯҳна аст. Агар қиматро аз props ва state ҳисоб кардан мумкин бошад — ҳисоб кунед, на нигоҳ доред.
Муфассал хонед: MDN — setTimeout · react.dev — You Might Not Need an Effect · learn.javascript.ru — filter
Амалиёт: мустаҳкам мекунем
ВАЗИФАИ 5.1 Функсияи filterStudents осон
Функсияи тозаи filterStudents(list, query)-ро нависед: аз рӯи ном ё шаҳр ҷустуҷӯ мекунад, бе назардошти ҳарфи калон ё хурд, фосилаҳои канори дархостро нодида мегирад, дархости холӣ ҳамаро бармегардонад.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
const STUDENTS = [
{ name: "Мадина" , city: "Душанбе" },
{ name: "Фарход" , city: "Худжанд" },
{ name: "Нилуфар" , city: "Душанбе" },
{ name: "Рустам" , city: "Бохтар" },
{ name: "Зарина" , city: "Худжанд" },
];
function filterStudents (list, query) {
// TODO
}
console.log (filterStudents (STUDENTS, "ду" ).map ((s) => s.name).join (", " ));
console.log (filterStudents (STUDENTS, " ФАР " ).map ((s) => s.name).join (", " ));
console.log (filterStudents (STUDENTS, "" ).length);
console.log (filterStudents (STUDENTS, "кабул" ).length);
Натиҷаи интизоршаванда Мадина, Нилуфар
Фарход, Нилуфар
5
0
Ишора 1 Дархостро омода кунед: const q = query.trim().toLowerCase();. Агар q === "" — list-ро баргардонед.
Ишора 2 list.filter((s) => s.name.toLowerCase().includes(q) || s.city.toLowerCase().includes(q))
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 5.2 Функсияи худии debounce миёна
debounce(fn, ms)-ро амалӣ кунед. Он функсияеро бармегардонад, ки fn-ро танҳо вақте даъват мекунад, ки пас аз даъвати охирин ms миллисония гузашта бошад. Стенд калимаи «плов»-ро «чоп мекунад», таваққуф мекунад ва «ш»-ро чоп мекунад.
Таҳрир кардан мумкин аст · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
function debounce (fn, ms) {
// TODO: функсияи навро баргардонед, ки даъвати fn-ро ба ms миллисония ба таъхир меандозад
// ва интизории гузаштаро ҳангоми ҳар даъвати нав аз нав мегузорад
}
const search = debounce ((q) => console.log ("поиск:" , q), 100 );
// стенд: истифодабаранда «плов»-ро чоп мекунад (ҳар 30 мс як ҳарф), таваққуф мекунад, баъд «ш»
["п" , "пл" , "пло" , "плов" ].forEach ((q, i) => {
setTimeout (() => search (q), i * 30 );
});
setTimeout (() => search ("ш" ), 500 );
Натиҷаи интизоршаванда поиск: плов
поиск: ш
Ишора 1 Тағйирёбандаи timer дар closure лозим аст (берун аз функсияи баргардонидашаванда). Ҳангоми ҳар даъват аввал clearTimeout(timer).
Ишора 2 return (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), ms); };
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 5.3 Ҳуки useDebounce миёна
Ҳуки useDebounce(value, delay)-ро амалӣ кунед. Эффекти поён бояд на барои ҳар ҳарф, балки танҳо вақте кор кунад, ки истифодабаранда хомӯш шуд.
Вазифаи 5.3 · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx
import { useEffect, useState } from "react" ;
function useScript (steps) {
useEffect (() => {
const ids = steps.map (([ms, fn]) => setTimeout (fn, ms));
return () => ids.forEach (clearTimeout);
}, []);
}
function useDebounce (value, delay) {
// TODO: қимати «ба таъхирафтода»-ро дар useState нигоҳ доред;
// дар useEffect setTimeout-ро оғоз кунед, ва дар cleanup — clearTimeout.
// Қимати ба таъхирафтодаро баргардонед.
}
export default function App () {
const [query, setQuery] = useState ("" );
const debounced = useDebounce (query, 100 );
// стенд: истифодабаранда «плов»-ро чоп мекунад, таваққуф мекунад, баъд «ш»-ро чоп мекунад
useScript ([
[40 , () => setQuery ("п" )],
[80 , () => setQuery ("пл" )],
[120 , () => setQuery ("пло" )],
[160 , () => setQuery ("плов" )],
[500 , () => setQuery ("ш" )],
]);
useEffect (() => {
console.log (`ищем: «${debounced}»` );
}, [debounced]);
return <input value={query} onChange={(e) => setQuery (e.target.value)} placeholder="Поиск" />;
}
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Натиҷаи интизоршаванда ищем: «»
ищем: «плов»
ищем: «ш»
Ишора 1 Ҳолати debounced аз қимати value оғоз мешавад. Эффект setTimeout-ро мегузорад, ки пас аз delay value-ро ба debounced нусха мекунад.
Ишора 2 Cleanup-и return () => clearTimeout(id) ва вобастагиҳои [value, delay]-ро фаромӯш накунед, ва дар охир — return debounced;
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
ВАЗИФАИ 5.4 Рефакторинг: ҳолати зиёдатиро хориҷ кунед миёна
Компонент visible-ро дар ҳолат нигоҳ медорад ва онро дар эффект нав мекунад. Оғоз кунед — дар консол рендерҳои зиёдатӣ ҳастанд, ва дар як сатр дархости «ду», аммо 4 ёфт шуд (маълумоти кӯҳна). Тавре аз нав нависед, ки visible ҳангоми рендер ҳисоб карда шавад, ва useState ва useEffect-и зиёдатӣ нопадид шаванд.
Вазифаи 5.4 · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx
import { useEffect, useState } from "react" ;
function useScript (steps) {
useEffect (() => {
const ids = steps.map (([ms, fn]) => setTimeout (fn, ms));
return () => ids.forEach (clearTimeout);
}, []);
}
const STUDENTS = [
{ id: 1 , name: "Мадина" , city: "Душанбе" },
{ id: 2 , name: "Фарход" , city: "Худжанд" },
{ id: 3 , name: "Нилуфар" , city: "Душанбе" },
{ id: 4 , name: "Рустам" , city: "Бохтар" },
];
export default function App () {
const [query, setQuery] = useState ("" );
const [visible, setVisible] = useState (STUDENTS);
// ✖ ҳолат ва эффекти зиёдатӣ: visible пурра аз query ҳосил мешавад
useEffect (() => {
setVisible (STUDENTS.filter ((s) => s.city.toLowerCase ().includes (query.toLowerCase ())));
}, [query]);
console.log (`рендер: запрос «${query}», найдено ${visible.length}` );
useScript ([[40 , () => setQuery ("ду" )]]); // стенд: истифодабаранда «ду»-ро ворид кард
return (
<div>
<input value={query} onChange={(e) => setQuery (e.target.value)} placeholder="Город" />
<ul>
{visible.map ((s) => (
<li key={s.id}>{s.name} — {s.city}</li>
))}
</ul>
</div>
);
}
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Натиҷаи интизоршаванда рендер: запрос «», найдено 4
рендер: запрос «ду», найдено 2
Ишора 1 useState-ро барои visible ва тамоми useEffect-ро хориҷ кунед.
Ишора 2 const visible = STUDENTS.filter((s) => s.city.toLowerCase().includes(query.toLowerCase())); — бевосита дар бадани компонент, пеш аз console.log.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
06 Блоки ЗС: промпт барои компоненти React дар муқобили кори дастӣ
Компонентҳои React-ро ЗС бисёр боэътимод менависад — ин яке аз маъмултарин дархостҳо дар ҷаҳон аст. Аммо маҳз дар ин ҷо ӯ «кунҷҳоро буридан»-ро дӯст медорад: response.ok-ро мегузарад, cleanup-ро фаромӯш мекунад, ҳолати «холӣ»-ро намекашад ё мусобиқаи дархостҳоро мегузорад. Код дар ин ҳол озода менамояд ва дар «роҳи хушбахт» кор мекунад. Бинобар ин маҳорати имрӯза — на «гирифтани компонент», балки ҳолатҳои ҳадди охирро дар промпт пешбинӣ кардан ва натиҷаро аз рӯи рӯйхат санҷидан аст.
Қоидаҳои курс, ки дар ин ҷо махсусан муҳиманд
1. Аввал 15 дақиқа худатон кӯшиш мекунед — Шумо аллакай қолабҳо аз бахшҳои 03–04 доред. 2. Баъд бо промпт аз рӯи формула ба ЗС мераведед. 3. Компонентеро, ки сатр ба сатр шарҳ дода наметавонед, ба лоиҳа нагузоред: Шумо бояд бидонед, ки ҳар вобастагӣ дар массив ва ҳар сатри cleanup барои чӣ аст. 4. Не дар «роҳи хушбахт», балки дар вайроншавиҳо санҷед: ҷавоби 404/500, рӯйхати холӣ, иваз шудани зуд, рафтан аз саҳифа.
Чӣ тавр хостан: бад ва хуб
Формулаи промпти курс: контекст → вазифа → маҳдудиятҳо → формати ҷавоб → санҷиш . Барои компоненти React се чизи ҳатмиро илова мекунем: props (аз берун чӣ меояд), ҳолат (компонент чӣ нигоҳ медорад) ва ҳолатҳои ҳадди охир (чӣ метавонад хато равад).
барои ман компоненти React бо рӯйхати истифодабарандагон бинависНусха бардоштан
Ман React меомӯзам, сатҳ — навомӯз: useState, props, key, useEffect-ро медонам. Компоненти функсионалии UserList-ро бо React-и тоза бе китобхонаҳо бинавис. Props: apiUrl (сатр). Ҳолат: status (loading | error | success), users, error. Маълумотро аз apiUrl дар useEffect тавассути fetch бор кун. Ҳатмӣ: санҷиши response.ok, чор ҳолати экран (боршавӣ, хато, холӣ, рӯйхат), бекор кардани дархост тавассути AbortController дар cleanup ва нодида гирифтани AbortError, массиви дурусти вобастагиҳо, key дар рӯйхат. Маҳдудиятҳо: як файл, на бештар аз 60 сатр, шарҳҳо ба забони русӣ барои ҳар блок. Формати ҷавоб: код, баъд рӯйхати «кадом ҳолати ҳадди охир бо кадом сатр коркард шудааст». Дар охир бигӯ, ки кадом сенарияҳоро ман бо даст санҷам.Нусха бардоштан
Пас аз ҷавоби ЗС компонентро аз чек-лист гузаронед. Агар ҳадди аққал як банд «не» бошад — Шумо хато ёфтед:
Чек-листи санҷиши компоненти ЗС
1) Чор ҳолат ҳаст: loading, error, empty, success? 2) response.ok санҷида мешавад, ва 404 ва 500 ба экрани хато меоранд? 3) Дар массиви вобастагиҳо ҳар чизе, ки эффект мехонад (url, id, query) ҳаст? 4) Cleanup бо abort() ҳаст ва AbortError ба истифодабаранда нишон дода намешавад? 5) Ҳангоми иваз шудани зуд ҷавоби кӯҳна навро напӯшонад ? 6) Дар рӯйхат key-и устувор ҳаст (на индекс, агар рӯйхат тағйир ёбад)? 7) useEffect(async …) ва ҳолати зиёдатӣ, ки онро ҳисоб кардан мумкин аст, нест? 8) Шумо метавонед ҳар сатрро шарҳ диҳед?
Дастӣ ё бо ЗС: муқоисаи ҳалолона
Дастӣ Бо ЗС Суръат 20–30 дақиқа барои компоненти аввал як дақиқа барои чорнавис, аммо илова вақт барои санҷиш Фаҳмиш Шумо медонед, ки ҳар сатр барои чӣ аст осон аст коди бегонаро «ба имон» қабул кардан Ҳолатҳои ҳадди охир танҳо он чиро ба ёд меоред, ки аллакай медонед бисёрро номбар мекунад, аммо хомӯшона он чиро, ки напурсидаед, мегузарад Кай интихоб кардан вазифаҳои таълимӣ, корҳои назоратӣ, ҳама чизи барои Шумо нав одат, ки Шумо онро худатон навишта метавонед; нигоҳи дуюм ба коди худ
Беҳтарин нақша — гибрид: компонентро худатон менависед, баъд аз ЗС мепурсед, ки онро танҳо санҷад аз рӯи чек-лист, на аз нав нависад. Ин тавр Шумо муаллиф мемонед, ва ЗС ҳамчун баррасикунандаи ҳушёр кор мекунад. Дар корҳои назоратӣ ЗС хомӯш аст.
Муфассал хонед: react.dev — You Might Not Need an Effect · react.dev — Fetching data with Effects
Амалиёт: хатоҳои ЗС-ро медорем
ВАЗИФАИ 6.1 Компоненти ЗС-ро санҷед ва ислоҳ кунед душвор
ЗС компоненти CourseList-ро дод ва итминон дод, ки «ҳама чиз ба назар гирифта шудааст». Стенд онро аз чор мавзӯъ мегузаронад: js (оҳиста), зуд ба react мегузарад, баъд none (рӯйхати холӣ) ва broken (сервер афтод, ҳолати 500). Оғоз кунед — Шумо фавран се мушкилиро мебинед. Танҳо CourseList-ро ислоҳ кунед: санҷиши ok, набудани мусобиқа ва AbortError, сатри алоҳида барои рӯйхати холӣ.
Вазифаи 6.1 · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx
import { useEffect, useState } from "react" ;
function useScript (steps) {
useEffect (() => {
const ids = steps.map (([ms, fn]) => setTimeout (fn, ms));
return () => ids.forEach (clearTimeout);
}, []);
}
// --- стенд: «сервер». Тағйир надиҳед ---
const DB = {
js: [{ id: 1 , title: "JavaScript с нуля" }, { id: 2 , title: "DOM и события" }, { id: 3 , title: "Асинхронность" }],
react: [{ id: 4 , title: "React: первые шаги" }, { id: 5 , title: "Хуки на практике" }],
none: [],
};
const DELAY = { js: 300 , react: 50 , none: 50 , broken: 50 };
function fakeFetch (url, { signal } = {}) {
const topic = new URL (url, "http://x" ).searchParams.get ("topic" );
return new Promise ((resolve, reject) => {
const t = setTimeout (() => {
if (topic === "broken" ) {
// сервер афтод: ҳолати 500, ва бадана — JSON нест
resolve ({
ok: false ,
status: 500 ,
json: () => Promise.reject (new SyntaxError ("Unexpected token 'I'" )),
});
} else {
resolve ({ ok: true , status: 200 , json: async () => DB[topic] });
}
}, DELAY[topic]);
signal?. addEventListener ("abort" , () => {
clearTimeout (t);
reject (new DOMException ("Aborted" , "AbortError" ));
});
});
}
// --- компоненти ЗС: ТАНҲО онро ислоҳ кунед ---
function CourseList ({ topic }) {
const [courses, setCourses] = useState ([]);
useEffect (() => {
fakeFetch (`/api/courses?topic=${topic}` )
.then ((response) => response.json ())
.then ((data) => {
console.log ("показано:" , data.map ((c) => c.title).join (", " ));
setCourses (data);
})
.catch ((err) => console.log ("показано: ошибка —" , err.message));
}, [topic]);
return (
<ul>
{courses.map ((c) => (
<li key={c.id}>{c.title}</li>
))}
</ul>
);
}
// --- стенд: истифодабаранда мавзӯъро иваз мекунад: js → react → none → broken ---
export default function App () {
const [topic, setTopic] = useState ("js" );
useScript ([
[20 , () => setTopic ("react" )],
[500 , () => setTopic ("none" )],
[700 , () => setTopic ("broken" )],
]);
return <CourseList topic={topic} />;
}
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Натиҷаи интизоршаванда показано: React: первые шаги, Хуки на практике
показано: пусто
показано: ошибка — HTTP 500
Ишора 1 Се хато: санҷиши response.ok нест (ҳангоми 500 хатои бегонаи JSON парида мебарояд); cleanup нест (ҷавоби «js» охирин мерасад ва экранро аз нав менависад); массиви холӣ сатри «показано: »-ро бе калимаҳо медиҳад.
Ишора 2 AbortController ва return () => controller.abort()-ро илова кунед; дар .catch — if (err.name === "AbortError") return;; пеш аз логи маълумот — шохаи if (data.length === 0)-ро.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
07 Амалиёт дар дарс: барномаро бо API ба React интиқол медиҳем
Дар дарсҳои 15–16 Шумо дар JS-и тоза барнома сохта будед: рӯйхати одамон аз API, ҷустуҷӯ, ҳолатҳои боршавӣ ва хато. Имрӯз чунин барномаро ба React интиқол медиҳем — қадам ба қадам. Ҳамаи қадамҳо зиндаанд: ба API-и воқеии dummyjson.com мераванд (дар он номҳои англисӣ ҳастанд). Ҳар қадам — версияи алоҳидаи барнома; оғоз кунед, тағйир диҳед, вайрон кунед.
DOM-версия ба React чӣ тавр «тарҷума» мешавад
Дар JS-и тоза буд Дар React шуд status.textContent = "Загрузка…"ҳолати status ва шохаи if (status === "loading") main(), ки ҳангоми боршавии саҳифа даъват шудаастuseEffect(..., [])тоза кардани рӯйхат ва давра бо append users.map(...) бо key дар JSXinput.addEventListener("input", ...)onChange ва ҳолати queryclearTimeout-и дастӣ барои debounceҳуки useDebounce бо cleanup тағйирёбандаи «дархости охирин» дар муқобили мусобиқа AbortController дар cleanup-и эффект
Гузариши асосии тафаккур: дар DOM-версия Шумо ба браузер мегуфтед, ки чиро тағйир диҳад («ин матнро гузор», «ин унсурро илова кун»). Дар React Шумо тавсиф мекунед, ки экран дар ҳолати додашуда чӣ тавр бояд намояд , ва тағйир додани DOM-ро React ба зимма мегирад.
Қадами 1. Рӯйхат ва ҳолатҳо
Боршавӣ, хато, холӣ, муваффақият — ҳама чизе, ки дар бахши 03 таҳлил кардем. Оғоз кунед ва фикр кунед: агар суроғаро ба нодуруст иваз кунем, чӣ мешавад?
Қадами 1: рӯйхат аз API · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx style.css
import { useEffect, useState } from "react" ;
export default function App () {
const [status, setStatus] = useState ("loading" ); // loading | error | success
const [users, setUsers] = useState ([]);
const [error, setError] = useState ("" );
useEffect (() => {
const controller = new AbortController ();
fetch ("https://dummyjson.com/users?limit=6&select=firstName,lastName,company" , {
signal: controller.signal,
})
.then ((response) => {
if (!response.ok) throw new Error ("HTTP " + response.status);
return response.json ();
})
.then ((data) => {
setUsers (data.users);
setStatus ("success" );
})
.catch ((err) => {
if (err.name === "AbortError" ) return ;
setError (err.message);
setStatus ("error" );
});
return () => controller.abort ();
}, []);
if (status === "loading" ) return <p className="note" >Загрузка…</p>;
if (status === "error" ) return <p className="note error" >Не получилось: {error}</p>;
if (users.length === 0 ) return <p className="note" >Список пуст</p>;
return (
<ul className="cards" >
{users.map ((u) => (
<li key={u.id} className="card" >
<b>{u.firstName} {u.lastName}</b>
<span>{u.company.title}</span>
</li>
))}
</ul>
);
}
body { font-family : system-ui, sans-serif; padding : 12px ; }
input { width : 100 %; box-sizing : border-box; padding : 8px 10px ; font : inherit; border : 1px solid #b8c0cc ; border-radius : 8px ; }
.cards { list-style : none; padding : 0 ; margin : 12px 0 0 ; display : grid; gap : 8px ; }
.card { padding : 10px 12px ; border : 1px solid #d5dae3 ; border-radius : 10px ; display : flex; flex-direction : column; gap : 2px ; }
.card span { color : #667 ; font-size : 14px ; }
button.card { font : inherit; text-align : left; background : #fff ; cursor : pointer; width : 100 %; }
button.card.on { border-color : #0a8f6a ; background : #e8f6f1 ; }
.note { color : #667 ; }
.error { color : #c0392b ; }
.detail { margin-top : 12px ; padding : 12px ; border-radius : 10px ; background : #f3f5f9 ; }
.detail p { margin : 4px 0 ; }
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Қадами 2. Ҷустуҷӯ бо debounce
Майдони ҷустуҷӯ, ҳуки useDebounce ва интихоби суроға илова шуд: дархости холӣ — рӯйхати оддӣ, ғайриҳолӣ — /users/search. Эффект ҳоло аз debounced вобаста аст, на аз query. ma, ol ва zzz-и бемаъниро кӯшиш кунед — ҳолати «холӣ»-ро мебинед.
Қадами 2: ҷустуҷӯ · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx style.css
import { useEffect, useState } from "react" ;
function useDebounce (value, delay) {
const [debounced, setDebounced] = useState (value);
useEffect (() => {
const id = setTimeout (() => setDebounced (value), delay);
return () => clearTimeout (id);
}, [value, delay]);
return debounced;
}
export default function App () {
const [query, setQuery] = useState ("" );
const debounced = useDebounce (query.trim (), 400 );
const [status, setStatus] = useState ("loading" );
const [users, setUsers] = useState ([]);
const [error, setError] = useState ("" );
useEffect (() => {
const controller = new AbortController ();
setStatus ("loading" );
const base = "https://dummyjson.com/users" ;
const select = "limit=6&select=firstName,lastName,company" ;
const url = debounced
? `${base}/search?q=${encodeURIComponent(debounced)}&${select}`
: `${base}?${select}` ;
fetch (url, { signal: controller.signal })
.then ((response) => {
if (!response.ok) throw new Error ("HTTP " + response.status);
return response.json ();
})
.then ((data) => {
setUsers (data.users);
setStatus ("success" );
})
.catch ((err) => {
if (err.name === "AbortError" ) return ;
setError (err.message);
setStatus ("error" );
});
return () => controller.abort ();
}, [debounced]);
let content;
if (status === "loading" ) content = <p className="note" >Загрузка…</p>;
else if (status === "error" ) content = <p className="note error" >Не получилось: {error}</p>;
else if (users.length === 0 ) content = <p className="note" >Никого не нашли по запросу «{debounced}»</p>;
else
content = (
<ul className="cards" >
{users.map ((u) => (
<li key={u.id} className="card" >
<b>{u.firstName} {u.lastName}</b>
<span>{u.company.title}</span>
</li>
))}
</ul>
);
return (
<div>
<input
value={query}
onChange={(e) => setQuery (e.target.value)}
placeholder="Поиск по имени (латиницей): ma, ol, ja…"
/>
{content}
</div>
);
}
body { font-family : system-ui, sans-serif; padding : 12px ; }
input { width : 100 %; box-sizing : border-box; padding : 8px 10px ; font : inherit; border : 1px solid #b8c0cc ; border-radius : 8px ; }
.cards { list-style : none; padding : 0 ; margin : 12px 0 0 ; display : grid; gap : 8px ; }
.card { padding : 10px 12px ; border : 1px solid #d5dae3 ; border-radius : 10px ; display : flex; flex-direction : column; gap : 2px ; }
.card span { color : #667 ; font-size : 14px ; }
button.card { font : inherit; text-align : left; background : #fff ; cursor : pointer; width : 100 %; }
button.card.on { border-color : #0a8f6a ; background : #e8f6f1 ; }
.note { color : #667 ; }
.error { color : #c0392b ; }
.detail { margin-top : 12px ; padding : 12px ; border-radius : 10px ; background : #f3f5f9 ; }
.detail p { margin : 4px 0 ; }
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Қадами 3. Корти шахси интихобшуда
Ба шахс дар рӯйхат пахш кунед: компоненти UserDetail дархости худии худро аз рӯи id мекунад. Он аз [id] вобаста аст, ва cleanup дархости гузаштаро бекор мекунад — яъне бо зуд клик кардан ба рӯйхат Шумо корти бегона намегиред. Қисми умумиро (санҷиши ok) мо ба функсияи getJson баровардем: ин тавр санҷиш дар як ҷост.
Қадами 3: рӯйхат + корт · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx style.css
import { useEffect, useState } from "react" ;
function useDebounce (value, delay) {
const [debounced, setDebounced] = useState (value);
useEffect (() => {
const id = setTimeout (() => setDebounced (value), delay);
return () => clearTimeout (id);
}, [value, delay]);
return debounced;
}
// печонандаи хурд: як маротиба ok-ро месанҷем ва JSON-ро бармегардонем
async function getJson (url, signal) {
const response = await fetch (url, { signal });
if (!response.ok) throw new Error ("HTTP " + response.status);
return response.json ();
}
function UserDetail ({ id }) {
const [status, setStatus] = useState ("loading" );
const [user, setUser] = useState (null );
useEffect (() => {
const controller = new AbortController ();
setStatus ("loading" );
getJson (`https://dummyjson.com/users/${id}?select=firstName,lastName,email,phone,address` , controller.signal)
.then ((data) => {
setUser (data);
setStatus ("success" );
})
.catch ((err) => {
if (err.name !== "AbortError" ) setStatus ("error" );
});
return () => controller.abort ();
}, [id]);
if (status === "loading" ) return <div className="detail" >Загружаем профиль…</div>;
if (status === "error" ) return <div className="detail error" >Профиль не загрузился</div>;
return (
<div className="detail" >
<p><b>{user.firstName} {user.lastName}</b></p>
<p>{user.email}</p>
<p>{user.phone}</p>
<p>{user.address.city}</p>
</div>
);
}
export default function App () {
const [query, setQuery] = useState ("" );
const debounced = useDebounce (query.trim (), 400 );
const [selectedId, setSelectedId] = useState (null );
const [status, setStatus] = useState ("loading" );
const [users, setUsers] = useState ([]);
const [error, setError] = useState ("" );
useEffect (() => {
const controller = new AbortController ();
setStatus ("loading" );
const base = "https://dummyjson.com/users" ;
const select = "limit=6&select=firstName,lastName,company" ;
const url = debounced
? `${base}/search?q=${encodeURIComponent(debounced)}&${select}`
: `${base}?${select}` ;
getJson (url, controller.signal)
.then ((data) => {
setUsers (data.users);
setStatus ("success" );
})
.catch ((err) => {
if (err.name === "AbortError" ) return ;
setError (err.message);
setStatus ("error" );
});
return () => controller.abort ();
}, [debounced]);
let content;
if (status === "loading" ) content = <p className="note" >Загрузка…</p>;
else if (status === "error" ) content = <p className="note error" >Не получилось: {error}</p>;
else if (users.length === 0 ) content = <p className="note" >Никого не нашли по запросу «{debounced}»</p>;
else
content = (
<ul className="cards" >
{users.map ((u) => (
<li key={u.id}>
<button
className={"card" + (u.id === selectedId ? " on" : "" )}
onClick={() => setSelectedId (u.id)}
>
<b>{u.firstName} {u.lastName}</b>
<span>{u.company.title}</span>
</button>
</li>
))}
</ul>
);
return (
<div>
<input
value={query}
onChange={(e) => setQuery (e.target.value)}
placeholder="Поиск по имени (латиницей): ma, ol, ja…"
/>
{content}
{selectedId && <UserDetail id={selectedId} />}
</div>
);
}
body { font-family : system-ui, sans-serif; padding : 12px ; }
input { width : 100 %; box-sizing : border-box; padding : 8px 10px ; font : inherit; border : 1px solid #b8c0cc ; border-radius : 8px ; }
.cards { list-style : none; padding : 0 ; margin : 12px 0 0 ; display : grid; gap : 8px ; }
.card { padding : 10px 12px ; border : 1px solid #d5dae3 ; border-radius : 10px ; display : flex; flex-direction : column; gap : 2px ; }
.card span { color : #667 ; font-size : 14px ; }
button.card { font : inherit; text-align : left; background : #fff ; cursor : pointer; width : 100 %; }
button.card.on { border-color : #0a8f6a ; background : #e8f6f1 ; }
.note { color : #667 ; }
.error { color : #c0392b ; }
.detail { margin-top : 12px ; padding : 12px ; border-radius : 10px ; background : #f3f5f9 ; }
.detail p { margin : 4px 0 ; }
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Ин қариб асоси омодаи кори хонагӣ аст
Қадами 3-ро ба лоиҳаи худ нусха кунед ва ба API-и худ ва мавзӯи худ тағйир диҳед: ба ҷои одамон — молҳо, қурби асъор, обу ҳаво, дастурҳои пухт. Аммо аввал версияро аз сифр аз рӯи ишораҳои поён ҷамъ кунед: ин тавр ба худ исбот мекунед, ки ҳар сатрро мефаҳмед.
Ҷамъ кардани барнома бо санҷиши худкор
Вазифаи охирини дарс худкор санҷида мешавад: Шумо эффект ва аломатгузории барномаро менависед, ва «истифодабаранда» (стенд) худаш дар майдон «д», баъд «ду» чоп мекунад ва натиҷаро муқоиса менамояд. Ҳамзамон месанҷем, ки debounce воқеан дархостҳоро сарфа мекунад: пас аз ҷустуҷӯ ба сервер айнан ду муроҷиат бояд бошад — боркунии аввалия ва як ҷустуҷӯ.
Амалиёт: барномаро ҷамъ мекунем
ВАЗИФАИ 7.1 Маълумотномаи иштирокчиён: ҷустуҷӯ + ҳолатҳо душвор
UsersApp-ро ба итмом расонед: (1) эффект аз рӯи [debounced], ки аввал status = "loading"-ро мегузорад, баъд "/api/users?q=" + encodeURIComponent(debounced)-ро бо AbortController, санҷиши ok, нодида гирифтани AbortError ва cleanup дархост мекунад; (2) аломатгузорӣ: <input> ва шохаҳои боршавӣ / хато / «Ничего не найдено» / рӯйхат аз <li>. Ҳуки useDebounce аллакай тайёр аст.
Вазифаи 7.1 · Ctrl + Enter ↺ Аз нав ▶ Иҷро кардан
App.jsx
import { useEffect, useState } from "react" ;
// ---------- стенд: «сервер». Тағйир надиҳед ----------
const USERS = [
{ id: 1 , name: "Мадина" , city: "Душанбе" },
{ id: 2 , name: "Фарход" , city: "Худжанд" },
{ id: 3 , name: "Нилуфар" , city: "Душанбе" },
{ id: 4 , name: "Рустам" , city: "Бохтар" },
];
let calls = 0 ; // чанд маротиба ба «сервер» муроҷиат карданд
function fakeFetch (url, { signal } = {}) {
calls++;
const q = (new URL (url, "http://x" ).searchParams.get ("q" ) || "" ).toLowerCase ();
const list = USERS.filter ((u) => (u.name + " " + u.city).toLowerCase ().includes (q));
return new Promise ((resolve, reject) => {
const t = setTimeout (() => resolve ({ ok: true , status: 200 , json: async () => list }), 100 );
signal?. addEventListener ("abort" , () => {
clearTimeout (t);
reject (new DOMException ("Aborted" , "AbortError" ));
});
});
}
// ---------- ҳук аз вазифаи 5.3 (аллакай тайёр) ----------
function useDebounce (value, delay) {
const [debounced, setDebounced] = useState (value);
useEffect (() => {
const id = setTimeout (() => setDebounced (value), delay);
return () => clearTimeout (id);
}, [value, delay]);
return debounced;
}
// ---------- барномаи ШУМО ----------
function UsersApp () {
const [query, setQuery] = useState ("" );
const debounced = useDebounce (query, 150 );
const [status, setStatus] = useState ("loading" );
const [users, setUsers] = useState ([]);
const [error, setError] = useState ("" );
// TODO 1: useEffect аз рӯи [debounced]: дархости "/api/users?q=" + encodeURIComponent(debounced)
// бо AbortController, санҷиши response.ok, коркарди AbortError ва cleanup.
// TODO 2: аломатгузориро баргардонед: майдони <input> (value/onChange бо query пайваст)
// ва дар зери он яке аз чор шоха: боршавӣ / хато / «Ничего не найдено» / рӯйхати <li>.
return null ;
}
// ---------- стенд: «истифодабаранда» дар майдон чоп мекунад. Тағйир надиҳед ----------
function typeInto (input, text) {
const setter = Object.getOwnPropertyDescriptor (HTMLInputElement.prototype, "value" ).set;
setter.call (input, text);
input.dispatchEvent (new Event ("input" , { bubbles: true }));
}
function Harness () {
useEffect (() => {
const input = document.querySelector ("input" );
const count = () => document.querySelectorAll ("li" ).length;
const ids = [
setTimeout (() => console.log ("карточек после загрузки:" , count ()), 300 ),
setTimeout (() => typeInto (input, "д" ), 400 ),
setTimeout (() => typeInto (input, "ду" ), 440 ),
setTimeout (() => {
console.log ("карточек после поиска «ду»:" , count ());
console.log ("запросов к серверу:" , calls);
}, 900 ),
];
return () => ids.forEach (clearTimeout);
}, []);
return null ;
}
export default function App () {
return (
<>
<UsersApp />
<Harness />
</>
);
}
Пешнамоиш Пӯшонидан
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Натиҷаи интизоршаванда карточек после загрузки: 4
карточек после поиска «ду»: 2
запросов к серверу: 2
Ишора 1 Сохтор ҳамон аст, ки дар қадамҳои 2 ва 3-и боло ва дар вазифаи 3.2. Барои кортҳо маҳз унсурҳои <li> лозиманд — стенд онҳоро мешуморад.
Ишора 2 Агар дархостҳо 3 шуданд, на 2 — эффект аз query ба ҷои debounced вобаста аст. Агар кортҳо 0 бошанд — санҷед, ки дар шохаи муваффақ users.map(...) бо <li key=...> кашида мешавад.
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
08 Шарҳи мухтасар: Next.js ва компонентҳои серверӣ минбаъд чӣ медиҳанд
Ҳар чизе, ки мо имрӯз кардем, — React-и клиентӣ аст: браузер JavaScript-ро мекашад, компонентро оғоз мекунад, ва танҳо баъд fetch оғоз мешавад. Истифодабаранда аввал «Загрузка…»-ро мебинад. Барои кабинетҳо ва барномаҳои паси вуруд ин муқаррарӣ аст. Барои сайтҳое, ки суръати намоиши аввал ва муҷаррикҳои ҷустуҷӯ муҳиманд (феҳристҳо, блогҳо, мағозаҳо), мехоҳем маълумотро пеш аз он ки саҳифа ба браузер равад, гирем.
Next.js — фреймворки маъмул болои React аст, ки ин корро ба зимма мегирад. Мухтасар, чӣ илова мекунад:
Имконият Дар амал ин чӣ маъно дорад Масиррӯбӣ аз рӯи папкаҳо папкаи app/courses/page.jsx — ин саҳифаи /courses аст; масиррӯбро бо даст танзим кардан лозим нест Компонентҳои серверӣ компонент дар сервер иҷро мешавад, худаш await fetch карда ё базаро хонда метавонад, ва ба браузер HTML-и тайёр меравад Компонентҳои клиентӣ ҳар чизе, ки дар он useState, useEffect, кликҳо ва воридот лозиманд, бо сатри "use client" қайд карда мешавад Экранҳои боршавӣ ва хатоҳо файлҳои loading.jsx ва error.jsx шохаҳои дастии ҳолатҳоро дар сатҳи саҳифа иваз мекунанд Коркардкунандаҳои серверӣ эндпоинтҳои худии API (route handlers) дар ҳамон лоиҳа Оптимизатсияҳо ва деплой фишурдани тасвирҳо, тақсими код, нашри қулай (масалан, дар Vercel)
Боркунии маълумот: усули имрӯза ва серверӣ
Компоненти серверӣ дар Next.js (ғоя, дар ин ҷо оғоз намешавад)
// app/students/page.jsx — компоненти серверӣ (бо пешфарз)
export default async function StudentsPage () {
const response = await fetch ("https://jsonplaceholder.typicode.com/users" );
const users = await response.json ();
return (
<ul>
{users.map ((u) => (
<li key={u.id}>{u.name}</li>
))}
</ul>
);
}
Бинед, ки дар ин ҷо чӣ нест: useState нест, useEffect нест, шохаи «Загрузка…» дар дохили компонент нест — компонент танҳо async аст ва маълумотро интизор мешавад. Сервер HTML-ро тайёр мекунад ва аллакай пуршуда медиҳад. Ҷустуҷӯ дар чунин рӯйхат, тугмаҳо ва ҳама чизи интерактивӣ ба ҳар ҳол бо компонентҳои клиентӣ навишта мешаванд — бо ҳамон useState ва useEffect, ки Шумо имрӯз омӯхтед.
Чӣ чизро бе ҳайп фаҳмидан муҳим аст
1. Компонентҳои серверӣ useEffect-ро бекор намекунанд — онҳо танҳо боркунии аввалияи маълумотро ба зимма мегиранд. Обунаҳо, таймерҳо, воридоти истифодабаранда дар клиент мемонанд. 2. Next.js ҳатмӣ нест: барномаи паси вуруд аксар вақт бо Vite + React қонеъ мешавад. 3. Дар лоиҳаҳои воқеӣ боркуниро дар useEffect аксар вақт бо китобхонаҳо мисли TanStack Query ё SWR иваз мекунанд: онҳо ҷавобҳоро кэш мекунанд, дархостҳоро такрор мекунанд ва мусобиқаҳоро хориҷ мекунанд. Аммо барои фаҳмидани он ки ин китобхонаҳо чӣ мекунанд, он чиро, ки имрӯз омӯхтед, донистан лозим аст. 4. Ин шарҳи мухтасар аст: дар Сатҳи 3 ҳама чиз муфассал ва бо амалиёт мешавад. (Дар баробари ин, платформае, ки дар он Шумо курсро мегузаронед, низ бо Next.js навишта шудааст.)
Vite + React (клиентӣ) Оддӣ ва зуд оғоз кардан мумкин аст. Барои кабинетҳо, панелҳо, абзорҳои дохилӣ мувофиқ аст. Маълумот дар браузер тавассути useEffect ё китобхона бор мешавад.
Next.js (клиент + сервер) Намоиши аввали зуд, SEO, масиррӯбии тайёр ва коди серверӣ дар як лоиҳа лозиманд. Маълумотро дар сервер гирифтан мумкин аст, ва интерактивиро клиентӣ гузоштан.
Муфассал хонед: Next.js — ҳуҷҷатгузорӣ · react.dev — Server Components
09 Харитаи роҳ: роҳ ба Сатҳи 3
Сатҳи 3 — ин React Pro + Next.js аст. Байни анҷоми ин курс ва оғози он Шумо вақт доред, ва беҳтар аст онро бо фоида гузаронед: на «ҳама чизро пай дар пай омӯхтан», балки аз рӯи нақша ҳаракат кардан. Дар поён — нақша барои 8 ҳафтаи омодагии мустақилона: мавзӯъҳо аз рӯи ҳафтаҳо ва як лоиҳа барои ҳар ду ҳафта.
Монанд аз ҳаёт
Роҳи Душанбе — Хоруғро як бор тай кардан мумкин нест: Кӯлоб, Дарвоз, истгоҳҳо, шабмонӣ ҳаст. Нақша — харитаи истгоҳҳост. Ҳатто агар Шумо оҳистатар аз нақша равед, медонед, ки дар куҷо ҳастед ва минбаъд ба куҷо рафтан лозим.
Нақша барои 8 ҳафта
Ҳафта Мавзӯъ Чӣ машқ кардан лозим 1 Такрор: компонентҳо, props, useState, шаклҳо майдонҳои идорашаванда (controlled inputs), шакл бо санҷиш, рӯйхат бо иловакунӣ ва нест кардан 2 useEffect, ҳукҳои худӣ, useReducerҳукҳои useDebounce, useLocalStorage, useFetch; Лоиҳаи 1 3 Масирҳо (React Router), ҳолати умумӣ тавассути Context якчанд саҳифа, саҳифаи мол аз рӯи id, мавзӯи тарроҳӣ тавассути Context 4 Кор бо маълумот: TanStack Query ё SWR, саҳифабандӣ кэш, такрори дархост, «боз бор кардан»; Лоиҳаи 2 5 TypeScript дар React намудҳо барои props ва ҷавобҳои API, interface, useState<User[]> 6 Муқаддимаи Next.js: саҳифаҳо, лейаутҳо, истинодҳо лоиҳаро дар Next.js эҷод кардан, 3 саҳифаро интиқол додан; Лоиҳаи 3 — интиқоли Лоиҳаи 2 ба Next.js 7 Компонентҳои серверӣ ва клиентӣ, loading.jsx, error.jsx маълумотро дар сервер гирифтан, интерактивро ба "use client" баровардан 8 Деплой, тағйирёбандаҳои муҳит, дастрасӣ, тарроҳӣ сайтро нашр кардан, README, скриншотҳо; Лоиҳаи 4 — маҳсулоти хурди ниҳоӣ дар портфолио
Нақшаро бо барномаи Сатҳи 3 муқоиса кунед
Ин нақшаи омодагӣ аст, на барномаи курс. Тартиби мавзӯъҳоро тағйир додан мумкин аст, ва он чи дар Сатҳи 3 мешавад, беҳтар аст аз омӯзгор равшан кунед. Агар шубҳа дошта бошед, ки ба Шумо чӣ лозимтар аст — useEffect ва кор бо API-ро такрор кунед: маҳз ба онҳо қариб ҳама чизи дигар такя мекунад.
Чӣ тавр машғул шудан лозим аст, то нақша кор кунад
30–60 дақиқа ҳар рӯз беҳтар аз 5 соат як маротиба дар як ҳафта аст. Майна такрор лозим дорад.
Як коммит дар як рӯз дар GitHub: репозиторий — портфолиои Шумост, ва қатори мураббаъҳои сабз интизомнок мекунад.
Коди бегонаро хонед: ягон лоиҳаи хурди React-ро дар GitHub кушоед ва кӯшиш кунед шарҳ диҳед, ки ҳар компонент чӣ мекунад.
Ҳуҷҷатгузорӣ — дӯст аст. Бахши «Learn» дар react.dev барои навомӯзон ва бо мисолҳои зинда навишта шудааст.
Қоидаҳои ЗС боқӣ мемонанд: аввал худатон, баъд промпт, бе фаҳмиши сатр ба сатр ҳеҷ чиз.
Ғояҳои лоиҳаҳо
Ғоя Чӣ меомӯзонад Трекери хароҷот бо сомонӣ бо нигоҳдорӣ дар localStorageшаклҳо, useReducer, ҳуки худӣ Обу ҳаво дар шаҳрҳои Тоҷикистон (API-и Open-Meteo, бе калид)useEffect, ҳолатҳои боршавӣ, интихоби шаҳрФеҳристи дастурпухтҳо -и қурутоб, палави ош, самбӯса бо ҷустуҷӯ ва филтрҳофилтркунӣ, параметрҳои URL, кортҳо Мини-мағоза бо сабад ва маблағи ниҳоӣContext, идоракунии ҳолат, аз нав ҳисобкуниҳо Ҷадвали машғулоти курс бо қайди дарсҳои иштирокшударӯйхатҳо, localStorage, сана ва вақт Луғати тоҷикӣ-русӣ бо ҷустуҷӯ бо debounceҷустуҷӯ, маълумоти ҳосилавӣ, оптимизатсия Тахтаи вазифаҳо (Kanban) ҳолати мураккаб, кашида бурдан, меъмории компонентӣ Мини-блог дар Next.js бо саҳифаҳои постҳомасирҳо, компонентҳои серверӣ, деплой
Аз ЗС хоҳиш кунед, ки нақша тартиб диҳад — ва онро санҷед
Промпти №26 аз шпаргалкаи курс. Он чорчӯба медиҳад, аммо қарор додан, ки воқеан чиро иҷро карда метавонед, ба зимма Шумост:
Ман курси «Frontend + AI»-ро (HTML/CSS, JavaScript, DOM, fetch, Git, асосҳои React: props, state, useEffect) тамом кардам. Нақшаи 8 ҳафтаро барои гузариш аз навомӯзи React ба React + Next.js-и боэътимод тартиб деҳ: мавзӯъҳо аз рӯи ҳафтаҳо ва барои ҳар 2 ҳафта як лоиҳа. Ман дар рӯзҳои корӣ 1 соат ва дар рӯзҳои истироҳат 3 соат машғул мешавам. Формати ҷавоб: ҷадвали «ҳафта — мавзӯъ — чӣ машқ кардан — натиҷа». Дар охир нависед, ки дар ин нақша чӣ аз ҳама хавфнок аст ва агар ман қафо монам, чиро хориҷ кардан мумкин аст.Нусха бардоштан
Санҷиш аз рӯи формулаи курс: нақшаро бо барномаи Сатҳи 3 муқоиса кунед , зиёдатиро хориҷ кунед, вақтро худатон баҳо диҳед. Нақшае, ки иҷро карда наметавонед, аз нақшаи хоксор, аммо зинда бадтар аст.
Муфассал хонед: react.dev — Learn · Next.js — Learn · MDN — Learn web development
Амалиёт: нақшаи Шумо
ВАЗИФАИ 9.1 Нақшаи 8 ҳафтаи ман осон
Ҷадвали нақшаи болоро гиред ва ба дафтар ё ба файли PLAN.md дар репозиторийи худ интиқол диҳед. Барои ҳар ҳафта ба ҷои суханони умумӣ мушаххас нависед: кадом рӯзҳо ва соати чанд машғул мешавед, кадом як чизро бо дасти худ мекунед, чӣ тавр мефаҳмед, ки ҳафта муваффақ шуд. Ғояи лоиҳаро барои Лоиҳаи 1 интихоб кунед ва нависед, ки он чӣ кор карда метавонад. Санҷиши худкор нест — вазифаро дастӣ қайд кунед, вақте ки нақша тайёр аст.
Ишора 1 Агар намедонед аз куҷо оғоз кунед, промпти №26-и болоро гиред ва ҷавоби онро бо фикрҳои худ муқоиса кунед — аммо нақшаи ниҳоиро бо суханони худ нависед.
Ишора 2 Банди хуби нақша месанҷем: «рӯзи сешанбе соати 19:00–20:00 — useLocalStorage-ро сохтан ва дар трекер истифода бурдан». Бад: «ҳукҳоро омӯхтан».
○ Ҳалшуда қайд кардан 💬 Дар бораи ин вазифа пурсидан
10 Вазифаи хонагӣ
Барномаи React-ро бо API ба итмом расонед, онро ба GitHub бор кунед ва нақшаи омодагӣ ба Сатҳи 3-ро тартиб диҳед. Артефакт: репозиторий бо барнома + файли PLAN.md.
Чӣ кор кардан лозим аст
API-и худро интихоб кунед бе калид ва бо CORS (дар браузер санҷед, ки ҷавоб меояд): jsonplaceholder.typicode.com, dummyjson.com, api.open-meteo.com, restcountries.com, rickandmortyapi.com. Мавзӯъ аз они Шумо: молҳо, кишварҳо, обу ҳаво, қаҳрамонҳо.
Лоиҳаи React-ро эҷод кунед (Vite, мисли дарси 17, қолаби React) ё дар муҳити онлайн ҷамъ кунед ва файлҳоро ба репозиторий интиқол диҳед.
Рӯйхат аз API тавассути useEffect + fetch: ҳадди ақал 6 корт бо 2+ майдон, key дар рӯйхат.
Чор ҳолат : боршавӣ, хато (бо гузоштани суроғаи нодуруст санҷед), «чизе ёфт нашуд», муваффақият. Тугмаи «Такрор» ҳангоми хато.
Ҷустуҷӯ бо debounce (ҳуки худии useDebounce) — тавассути дархост ба сервер ё филтркунии рӯйхат.
Бекор кардани дархостҳо: AbortController дар cleanup, AbortError ба истифодабаранда нишон дода намешавад.
Санҷиши ЗС. Агар ЗС-ро истифода бурда бошед — промпт (формула: контекст → вазифа → маҳдудиятҳо → формат → санҷиш) ва чек-листи гузашта аз бахши 06-ро замима кунед.
Нақшаи PLAN.md: 8 ҳафта, дар ҳар кадом — амалҳои мушаххас, ғояи интихобшудаи Лоиҳаи 1 ва истинодҳо ба 2–3 манбаъ, ки мехонед.
Ба GitHub бор кунед (дарси 19): коммитҳои пурмазмун, ҳадди ақал 5, файли README бо скриншотҳо ва тавсиф.
Чӣ супоридан лозим
Истиноди репозиторийи GitHub бо барнома, README ва PLAN.md.
Ду скриншот: саҳифа бо маълумот ва саҳифа бо ҳолати хато.
Тавсифи кӯтоҳ дар README: кадом API-ро интихоб кардед, кадом ҳолатҳои ҳадди охирро коркард кардед.
Чӣ тавр баҳо медиҳем (0–10)
Чӣ Холҳо Боркунии маълумот дар useEffect, массиви дурусти вобастагиҳо, key дар рӯйхат 2 Чор ҳолати экран кор мекунанд (аз ҷумла санҷиши response.ok) 2 Ҷустуҷӯ бо debounce, дархостҳои зиёдатӣ нестанд 2 Cleanup: AbortController, коркарди AbortError 1 Репозиторий дар GitHub: коммитҳо, README бо скриншотҳо 1 PLAN.md: нақшаи мушаххаси 8 ҳафта ва ғояи лоиҳа1 Коди тоза: номҳои фаҳмо, ҳолати зиёдатӣ нест; коди ЗС-ро сатр ба сатр шарҳ дода метавонед 1
Пеш аз супоридан
Интернетро хомӯш кунед (ё дар DevTools дар ҷадвали Network реҷаи Offline-ро гузоред) ва барномаро аз нав бор кунед. Ба ҷои экрани холӣ паёми фаҳмо бо тугмаи «Такрор» бояд пайдо шавад. Баъд дар ҷустуҷӯ зуд якчанд ҳарфро пай дар пай чоп кунед ва ба ҷадвали Network нигаред: дархост бояд як маротиба равад, на барои ҳар ҳарф.
✓ Шпаргалкаи дарс
Рендер бояд тоза бошад. Дархостҳо, таймерҳо, document.title, обунаҳо — таъсироти ҷонибӣ ҳастанд, ҷояшон дар useEffect аст.
Тартиб: рендер → навкунии DOM → эффект.
Вобастагиҳо: бе массив — пас аз ҳар рендер; [] — як маротиба; [a, b] — ҳангоми тағйири a ё b. Дар массив ҳар чизе, ки эффект мехонад.
Cleanup: return () => ... дар эффект. Пеш аз оғози такрорӣ ва ҳангоми рафтани компонент даъват мешавад. StrictMode дар таҳия қасдан «эффект → cleanup → эффект»-ро оғоз мекунад.
Чор ҳолат: loading, error, empty, success. «Холӣ» — ин муваффақият бо массиви холӣ аст.
Қолаб: fetch → if (!response.ok) throw new Error(...) → json() → setState; дар .catch — хато, аммо AbortError-ро нодида мегирем.
Мумкин нест useEffect(async () => ...): функсияи async-ро дар дохил эълон мекунем.
Мусобиқаи дархостҳо: cleanup бо controller.abort() (ё парчами ignore), то ҷавоби кӯҳна навро напӯшонад.
Маълумоти ҳосилавӣ (рӯйхати филтршуда) ҳангоми рендер ҳисоб мекунем, ва дар ҳолат нигоҳ намедорем.
Debounce: useDebounce(value, delay) — setTimeout дар эффект ва clearTimeout дар cleanup; дархост аз debounced вобаста аст.
Next.js: масирҳо аз рӯи папкаҳо, компонентҳои серверӣ (маълумот дар сервер, бе useEffect), "use client" барои интерактив.
Бо ЗС: дар промпт барои компонент — props, ҳолат, ҳолатҳои ҳадди охир; санҷиш аз рӯи чек-лист аз 8 банд.
Минбаъд: 8 ҳафтаи нақша, лоиҳа як маротиба дар ду ҳафта, коммит дар як рӯз.
🎓 Табрик мекунем: Шумо курсро тамом кардед
Ҳашт ҳафта пеш Шумо HTML ва CSS-ро медонистед ва ҳанӯз ягон сатри JavaScript нанавишта будед. Имрӯз Шумо барномаи React сохтед, ки маълумотро аз API-и воқеӣ бор мекунад, ҷустуҷӯ карда метавонад, ҳангоми вайроншавии шабака намешиканад ва дархостҳои нолозимро бекор мекунад. Ин роҳи ҷиддӣ аст, ва Шумо онро худатон тай кардед — бо ҳар вазифа, ҳар хато дар консол ва ҳар «чаро кор намекунад?», ки дар ниҳоят кор кард.
Шумо акнун чӣ карда метавонед
Забон ва браузер Тағйирёбандаҳо, шартҳо, давраҳо, функсияҳо, массивҳо ва объектҳо. DOM, ҳодисаҳо, шаклҳо, ҳолати барнома, localStorage.
Ғайримутобиқӣ ва маълумот Promise-ҳо, async/await, fetch, ҳолатҳои HTTP, JSON, коркарди хатоҳо, печонанда болои дархостҳо.
Абзорҳои даста Модулҳо ва Vite, Git ва GitHub, ислоҳи хато, баррасии код, README, ду лоиҳа бо ҳимоя.
Кор бо ЗС Промпт аз рӯи формула, санҷиши ҷавоб, қоидаи «бе фаҳмиш ҳеҷ чиз», шпаргалкаи шахсӣ аз промптҳои корӣ.
React Компонентҳо, props, useState, рӯйхатҳо бо key, useEffect, боркунии маълумот, cleanup, ҷустуҷӯ бо debounce.
Монанд аз ҳаёт
Палави хуб аз бори аввал намебарояд — он аз даҳум мебарояд, вақте ки даст худаш медонад, ки чӣ қадар равған ва кай биринҷ илова кардан лозим. Барномасозӣ ҳамин гуна аст: акнун Шумо дастурпухтҳо доред, ва «даст» бо машқ ташаккул меёбад. Онро партоед.
Се маслиҳат барои роҳ
Ҳар рӯз код нависед, ҳатто каме-каме. Мунтазамӣ аз дарозии машғулотҳо муҳимтар аст.
Лоиҳаҳоро дар бораи он чӣ ба Шумо шавқовар аст, созед. Он гоҳ ҷойҳои мушкил наметарсонанд, балки ҷалб мекунанд.
Аз хатоҳо ва саволҳо наҳаросед. Паёми сурх дар консол — баҳо ба Шумо нест, балки ишора аст. Ва вақте ки монед — хаторо тавре тавсиф кунед, ки мо омӯхтем: чиро интизор будед, чиро гирифтед, кадом код.
Имрӯз чӣ кор кардан лозим
PLAN.md-ро кушоед, вақти машғулияти аввалро барои фардо қайд кунед — ва коммити аввалро кунед. Ташаккур барои кӯшиш, саволҳо ва сабр. Қадамҳои боэътимодро ба Сатҳи 3 орзу мекунем — дар он ҷо мебинем!