Mundarija (33)
- Bu darsda
- 1. Nega bu kerak?
- 2. Action nima
- 2.1 Ta'rif
- 2.2 Qo'lda va Action bilan
- 3. Action ichidagi yangilanishlar
- 3.1 "Saqlanmoqda…" ko'rinmadi
- 3.2 Nega
- 3.3 await dan keyin — yana startTransition
- 3.4 Bir nechta Action
- 4. <form action> — Action'ning tabiiy uyi
- 4.1 Qisqa takror
- 4.2 formAction: bitta forma — ikki Action
- 4.3 Avtomatik reset: kimga tegadi
- 4.4 requestFormReset: o'zingiz tozalang
- 5. Action ichidagi xato
- 5.1 Tashlangan xato — chegaragacha
- 5.2 Kutilgan xato — qiymat
- 6. Action'ni nomlash va props
- 7. Vazifalar qadami: yozuvlar — Action (1-qism)
- 7.1 Muammo: v7 dagi yozuv
- 7.2 fondaYoz — hodisadan Action
- 7.3 yozuvniYubor — tasdiq yana transition'da
- 7.4 flushSync ketdi, fokus qoldi
- 8. Ko'p uchraydigan xatolar
- 9. Mashqlar
- 1-mashq (oson): nima ko'rinadi?
- 2-mashq (o'rta): ikki tugma — ikki Action
- 3-mashq (qiyin): "Saqlanmoqda…" va xato
- 4-mashq: Vazifalar qadami
- 10. Real ishda
- Xulosa
- Manbalar
Actions: async transitionlar va form action — React 19 da kutish, xato va forma reset
Qisqacha: React 19 da transition ichida chaqirilgan funksiya Action deyiladi. U oddiy ham,
asyncham bo'lishi mumkin. React Action'ni kuzatadi:awaitqilingan so'rov qaytgunchaisPending—true. Action ichidagi hamma yangilanish esa u tugagach birga chiziladi.<form action={fn}>va tugmadagiformAction={fn}— Action'ni ishga tushirishning tayyor yo'li: ReactFormDatani o'zi beradi, transition'ni o'zi ochadi va muvaffaqiyatdan keyin uncontrolled maydonlarni o'zi tozalaydi. Formani qo'lda tozalash kerak bo'lsa —requestFormReset(form), faqat Action ichida. Action ichida tashlangan xato eng yaqin error boundary'ga ketadi.
Bu darsda
- Action nima ekanini va reducer'dagi "amal (action)" dan farqini tushuntira olasiz.
startTransition(async () => …)daisPendingva yangilanishlar qachon chizilishini jonli ko'rasiz — jumladan "Saqlanmoqda…" nega ko'rinmay qolishini.<form action>vaformActionbilan bir formada ikki xil yuborish yozasiz.- Avtomatik reset qaysi maydonlarga tegishini va
requestFormResetqachon kerakligini bilasiz. - Action ichidagi xato qayerga ketishini ko'rasiz va
vazifalardagi server yozuvini Action'ga aylantirasiz (1-qism).
Oldin bilishingiz kerak: useTransition, Formalar II: form action, async / await, useReducer.
1. Nega bu kerak?
Oldingi darsda ma'lumotni o'qishni ko'rdik: Promise, use, Suspense. Endi teskari yo'nalish — ma'lumotni serverga yozish. Jasur aka «Bahor» saytida stol bron qilish formasini xohlaydi.
Sardor uni o'zi bilgan usulda yozdi. Unda isSaving state'i, try/finally va xato uchun yana bir state bor. Yana ikki marta bosishdan himoya va oxirida maydonlarni qo'lda bo'shatish. 40 qatorning 25 tasi bron haqida emas, "kutish" va "tozalash" haqida edi. Bunday kod har formada takrorlanadi va har safar bir joyi unutiladi. Bir formada finally yo'q edi: server xato qaytardi va tugma abadiy bloklangan qoldi.
Hayotiy o'xshatish: pochta bo'limida jo'natma topshirish. Siz qutini beraverasiz. Xodim o'zi tarozida tortadi, o'zi chek yozadi, o'zi qutini javonga qo'yadi va "keyingisi!" deydi. Siz "tortilyaptimi, chek yozildimi" deb har qadamni kuzatmaysiz. Action — React'ga beriladigan shunday quti: siz faqat "nima yuboriladi" ni yozasiz, kutish, tartib va tozalashni React o'zi bajaradi.
2. Action nima
2.1 Ta'rif
Action — transition ichida chaqiriladigan funksiya. useTransition darsida startTransition ga async funksiya bergan edik va React hujjati uni shunday atashini aytgan edik. Bugun shu g'oyani oxirigacha ko'ramiz.
Action'ni React ishga tushiradigan uch yo'l bor:
| Qayerda | Kim chaqiradi |
|---|---|
startTransition(fn) yoki useTransition |
siz, hodisa ishlovchisida |
<form action={fn}>, <button formAction={fn}> |
React, forma yuborilganda |
useActionState qaytargan funksiya |
React yoki siz (keyingi dars) |
Diqqat: useReducer darsida
dispatch({ tur: "qoshildi" })dagi obyektni amal (action) deb atagan edik. Bu boshqa narsa: u — "nima bo'ldi" degan oddiy obyekt. Bugungi Action esa funksiya, odatdaasync. Nomlari bir xil, chunki ikkalasi ham "foydalanuvchi qilgan ish" ni bildiradi. Darsda funksiyani doim katta harf bilan — Action — yozamiz.
2.2 Qo'lda va Action bilan
Avval eski usulni ko'ramiz. Bu — Sardorning formasi, qisqartirilgan:
const [isSaving, setIsSaving] = useState(false);
const [error, setError] = useState(null);
async function handleClick() {
setIsSaving(true);
setError(null);
try {
await saveBooking();
} catch (err) {
setError(err.message);
} finally {
setIsSaving(false); // ❌ unutilsa — tugma abadiy bloklangan
}
}Action bilan isSaving va finally yo'qoladi — kutish holatini React o'zi biladi:
const [isPending, startTransition] = useTransition();
function handleClick() {
startTransition(async () => {
await saveBooking(); // isPending shu qaytguncha true
});
}Qolgan farqlar jadvalda:
| Savol | Qo'lda | Action |
|---|---|---|
| "kutilmoqda" holati | useState + finally |
React o'zi (isPending) |
| bir necha bosish | har biri o'z setIsSaving i |
isPending hammasi tugaguncha true |
| oraliq kadrlar | har setter alohida chiziladi | hammasi Action tugagach, birga |
| xato | catch + state |
error boundary yoki qiymat (useActionState) |
| forma tozalash | qo'lda | <form action> da avtomatik |
Jadvaldagi uchinchi qator — eng kutilmagani. Uni alohida ko'ramiz.
3. Action ichidagi yangilanishlar
3.1 "Saqlanmoqda…" ko'rinmadi
Tabiiy fikr: "So'rovdan oldin xabarni o'rnataman, keyin await":
import { useState, useTransition } from "react";
function saveBooking() {
return new Promise((resolve) => setTimeout(resolve, 300));
}
export default function App() {
const [message, setMessage] = useState("Bron yo'q");
const [isPending, startTransition] = useTransition();
console.log("render:", isPending, message);
function handleClick() {
startTransition(async () => {
setMessage("Saqlanmoqda…"); // ❌ ko'rinmaydi
await saveBooking();
startTransition(() => setMessage("5-stol bron qilindi"));
});
}
return (
<div>
<button onClick={handleClick}>Saqlash</button>
<p>{message}</p>
</div>
);
}Konsolda:
render: false Bron yo'q
render: true Bron yo'q
render: true Bron yo'q
render: false 5-stol bron qilindiEkranda:
Saqlash
5-stol bron qilindiHarakat qatoridagi ekran("Bron yo'q") — bosilgandan 60 ms keyin, ya'ni so'rov hali yo'lda. Ekranda hali eski matn turibdi. Konsolda ham "Saqlanmoqda…" bir marta ham yo'q.
3.2 Nega
setMessage("Saqlanmoqda…") transition ichida chaqirildi — u ham Action'ning bir qismi. React Action'ga tegishli yangilanishlarni ushlab turadi va Action tugaganda hammasini bitta renderda chizadi. Oxirgi qiymat "5-stol bron qilindi" — oraliq qiymat hech qachon ekranga chiqmaydi.
sequenceDiagram
participant U as Foydalanuvchi
participant R as React
participant S as Server
U->>R: bosish
R->>R: isPending: true (shoshilinch render)
R->>S: Action: setMessage + await
Note over R: Action yangilanishlari kutadi
S-->>R: javob (300 ms)
R->>R: hammasi birga: isPending false + yangi matnDiagrammada asosiy ikki nuqta bor: bosilganda (isPending: true) va Action tugaganda. Orada React yangi matnni chizmaydi. Bu ataylab qilingan: foydalanuvchi "Saqlanmoqda… → Bron yo'q → 5-stol" kabi sakrashni ko'rmaydi.
Unda "kutilmoqda" ni qanday ko'rsatamiz? Uchta yo'l:
isPending— React o'zi beradi ({isPending ? "Saqlanmoqda…" : message}).useFormStatus— forma ichidagi tugma uchun (keyingi dars).useOptimistic— Action davomida darhol ko'rinadigan qiymat (useOptimistic).
vazifalar ning kanonida aynan shu tuzoq topildi. Forma Action'i ichida «qo'shildi» e'lonini oddiy setter bilan qo'yish e'lonni server javobigacha yashirardi. Shuning uchun u useOptimistic ga o'tdi — buni useOptimistic darsida ko'ramiz.
3.3 await dan keyin — yana startTransition
Kodda await dan keyingi setter startTransition(() => …) ichida. Sababi useTransition darsidagi "ma'lum cheklov": await dan keyin React "transition ichidamiz" ekanini unutadi. O'ralmasa, setter shoshilinch bo'lib, Action tugashini kutmasdan chiziladi. Qoida o'zgarmadi: await dan keyingi har setter — yana startTransition ichida.
Tekshirib ko'ring: Konsolda nega aynan to'rt qator? Qaysi render
isPendingnitrueqildi?
Javob
1-qator — birinchi chizish. 2-qator — bosish paytidagi shoshilinch render: React faqat isPending: true ni chizdi. 3-qator — transition renderi: React Action'ni boshladi, lekin u hali await da. Shu render ham message ni eski holda ko'radi — "Saqlanmoqda…" Action'ga bog'langan va kutib turibdi. 4-qator — Action tugadi: isPending: false va oxirgi message bitta renderda. "Saqlanmoqda…" uchun render bo'lmadi — uning ustidan yozildi.
3.4 Bir nechta Action
Foydalanuvchi tugmani tez-tez ikki marta bossa-chi? Har bosish — alohida Action. React ularni birlashtiradi: isPending ikkalasi ham tugaguncha true turadi.
import { useState, useTransition } from "react";
let saved = 0; // "server"dagi buyurtmalar
function addToServer() {
return new Promise((resolve) => {
setTimeout(() => resolve(++saved), 500);
});
}
export default function App() {
const [count, setCount] = useState(0);
const [isPending, startTransition] = useTransition();
function handleClick() {
startTransition(async () => {
const total = await addToServer();
console.log("server javobi:", total);
startTransition(() => setCount(total));
});
}
return (
<div>
<button onClick={handleClick}>+1 osh</button>
<p>
{isPending ? "Saqlanmoqda…" : `Buyurtmada: ${count} osh`}
</p>
</div>
);
}Konsolda:
server javobi: 1
server javobi: 2Ekranda:
+1 osh
Buyurtmada: 2 oshVaqt bo'yicha (taxminan): 0 ms — 1-bosish, 360 ms — 2-bosish, 500 ms — 1-javob, 860 ms — 2-javob. Harakat qatoridagi ikkinchi ekran ~680 ms da — 1-javob kelib bo'lgan. Lekin ekranda hali "Saqlanmoqda…" — "1 osh" bir zumga ham chiqmadi. React ikkinchi Action tugashini kutdi va oxirgi holatni bir marta chizdi.
Bu odatda yaxshi: ekran sakramaydi. Lekin Action'lar parallel ishlayotganini unutmang. Server javoblari teskari tartibda kelsa, eski javob yangisining ustiga yozilishi mumkin. Navbatni React o'zi qiladigan vosita — useActionState: u Action'larni ketma-ket bajaradi.
4. <form action> — Action'ning tabiiy uyi
4.1 Qisqa takror
Formalar II darsida ko'rgansiz: <form action={fn}> ga funksiya bersangiz, React yuborishni ushlaydi, preventDefault qiladi va funksiyaga FormData beradi. Bugun bitta muhim gapni qo'shamiz: React bu funksiyani transition ichida chaqiradi. Ya'ni forma Action'i «Action ichidagi yangilanishlar» bo'limidagi qoidalarning hammasiga bo'ysunadi:
- ichidagi setterlar Action tugagach birga chiziladi;
awaitdan keyingi setter — yanastartTransitionichida;- xato — error boundary'ga.
Form action uchun yana uchta imkoniyat bor: tugmadagi formAction, avtomatik reset va requestFormReset.
4.2 formAction: bitta forma — ikki Action
Jasur akaning bron formasida ikki tugma bor: «Bron qilish» va «Qoralamaga». Ma'lumot bir xil, ishi boshqa. Tugmaning formAction prop'i formaning action ini shu tugma uchun almashtiradi:
import { useState } from "react";
export default function App() {
const [log, setLog] = useState([]);
function book(formData) {
setLog((l) => [...l, `bron: ${formData.get("name")}`]);
}
function saveDraft(formData) {
setLog((l) => [...l, `qoralama: ${formData.get("name")}`]);
}
return (
<form action={book}>
<label>
Ism <input name="name" />
</label>
<button>Bron qilish</button>{" "}
<button formAction={saveDraft}>Qoralamaga</button>
<ul>
{log.map((line, i) => (
<li key={i}>{line}</li>
))}
</ul>
</form>
);
}Ekranda:
Ism Bron qilish Qoralamaga
qoralama: Malika
bron: BoburHar tugma o'z Action'ini chaqirdi, FormData esa ikkalasida bir xil forma maydonlaridan olindi. HTML'da formaction atributi bor edi — u boshqa manzil (URL) berardi. React'da unga funksiya beriladi. Ikkinchi narsaga e'tibor bering: Bobur yozilganda maydonda "Malika" yo'q edi — birinchi Action'dan keyin forma tozalangan.
4.3 Avtomatik reset: kimga tegadi
Action muvaffaqiyatli tugagach React formani reset qiladi — brauzerning form.reset() i kabi. Lekin faqat uncontrolled maydonlarni. Controlled maydon (value + onChange) qiymati state'da — React uni o'zi chizadi, reset unga tegmaydi.
import { useState } from "react";
export default function App() {
const [name, setName] = useState("");
function send(formData) {
const name = formData.get("name");
console.log("yuborildi:", name, "|", formData.get("note"));
}
function showFields() {
const name = document.querySelector("[name=name]").value;
const note = document.querySelector("[name=note]").value;
console.log("ism:", name, "| izoh:", note);
}
return (
<>
<form action={send}>
<label>
Ism{" "}
<input
name="name"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
<label>
Izoh <input name="note" />
</label>
<button>Yuborish</button>
</form>
<button onClick={showFields}>Maydonlar?</button>
</>
);
}Konsolda:
yuborildi: Ali | Deraza oldi
ism: Ali | izoh:name — controlled, "Ali" joyida qoldi. note — uncontrolled, bo'shab qoldi. Controlled maydonni tozalash kerak bo'lsa — Action ichida setName("").
Reset faqat Action muvaffaqiyatli tugaganda bo'ladi. Action xato tashlasa, forma o'zgarmaydi — buni «Action ichidagi xato» bo'limida ko'ramiz. Action qiymat qaytarsa ham (masalan, "Ism kerak"), React uni muvaffaqiyat deb biladi va tozalaydi. Bu — Formalar II dagi "xato bo'lsa ham matn yo'qoladi" tuzog'i. Yechimi o'sha darsda edi: yozilgan qiymatni useActionState bilan qaytarib, defaultValue ga berish. Keyingi darsda vazifalar aynan shuni qiladi.
4.4 requestFormReset: o'zingiz tozalang
Ba'zan forma onSubmit bilan yoki tugmadagi onClick bilan ishlaydi. Shunda ham React'dagi reset kerak bo'lishi mumkin. Buning uchun react-dom da requestFormReset(form) bor: "shu Action tugagach formani tozala". U faqat Action ichida ishlaydi:
import { useRef } from "react";
import { requestFormReset } from "react-dom";
export default function App() {
const formRef = useRef(null);
function showField() {
const field = formRef.current.querySelector("[name=dish]");
console.log("maydonda:", JSON.stringify(field.value));
}
return (
<>
<form ref={formRef}>
<label>
Taom <input name="dish" />
</label>
<button
type="button"
onClick={() => requestFormReset(formRef.current)} // ❌
>
Tozalash
</button>
</form>
<button onClick={showField}>Maydon?</button>
</>
);
}Konsolda:
requestFormReset was called outside a transition or action. To fix, move to an action, or wrap with startTransition.
maydonda: """requestFormReset transition yoki Action'dan tashqarida chaqirildi. Tuzatish uchun uni Action'ga ko'chiring yoki startTransition ga o'rang."
Maydon bu safar baribir tozalandi: React dev'da ogohlantirdi va reset'ni oddiy, shoshilinch yangilanish sifatida bajardi. Ogohlantirish — "kod noto'g'ri" belgisi. Production'da u chiqmaydi, reset esa Action natijasidan alohida chiziladi. Xabarning o'zi davoni aytyapti:
import { startTransition, useRef } from "react";
import { requestFormReset } from "react-dom";
export default function App() {
const formRef = useRef(null);
function showField() {
const field = formRef.current.querySelector("[name=dish]");
console.log("maydonda:", JSON.stringify(field.value));
}
function handleReset() {
startTransition(() => {
requestFormReset(formRef.current); // ✅ Action ichida
});
}
return (
<>
<form ref={formRef}>
<label>
Taom <input name="dish" />
</label>
<button type="button" onClick={handleReset}>
Tozalash
</button>
</form>
<button onClick={showField}>Maydon?</button>
</>
);
}Konsolda:
maydonda: ""Nega bunday cheklov? Reset — Action natijasi bilan birga chizilishi kerak. Action davom etayotganda tozalansa, foydalanuvchi bo'sh maydonni va eski ro'yxatni bir vaqtda ko'radi. React reset'ni Action'ning boshqa yangilanishlari bilan bitta commit'ga qo'yadi.
form.reset() dan farqi ham shu: form.reset() DOM'ni darhol tozalaydi, React esa bundan bexabar qoladi. requestFormReset — React'ning navbati orqali.
Tekshirib ko'ring: Formada uchta maydon bor: ism (controlled), telefon (uncontrolled,
defaultValue=""), izoh (uncontrolled,defaultValue="Deraza oldi"). Action muvaffaqiyatli tugadi. Maydonlarda nima qoladi?
Javob
Ism — yozilgan qiymat (controlled, state'dan). Telefon — bo'sh. Izoh — "Deraza oldi": reset maydonni bo'sh emas, boshlang'ich qiymatga qaytaradi. React defaultValue ni HTML value atributiga yozadi, brauzer esa reset'da aynan shu atributni oladi (Formalar II, form.reset() bo'limi).
5. Action ichidagi xato
5.1 Tashlangan xato — chegaragacha
Server 500 qaytardi va Action throw qildi. Kim ushlaydi?
async function book(formData) {
await new Promise((resolve) => setTimeout(resolve, 200));
throw new Error("500: server xatosi");
}
export default function App() {
return (
<form action={book}>
<label>
Ism <input name="name" />
</label>
<button>Bron qilish</button>
</form>
);
}Konsolda:
Uncaught Error: 500: server xatosiNatija oynasida — "Komponentni chizishda xato" qutisi, forma yo'q. React Action'dagi xatoni render xatosi kabi ko'rdi: eng yaqin error boundary'ni qidirdi, topmadi va butun ilovani o'chirdi (React ilovani debug qilish dagi oq ekran). useTransition bergan startTransition dagi xato ham xuddi shunday.
Bitta istisno bor: hook'siz startTransition (import { startTransition } from "react"). U hech qaysi komponentga bog'lanmagan — React xatoni qaysi chegaraga berishni bilmaydi. Xato Uncaught Error bo'lib konsolga tushadi, ilova esa joyida qoladi. Foydalanuvchi esa hech narsa ko'rmaydi — bu yanada yomon. Shuning uchun hook'siz startTransition dagi Action xatoni o'zi ushlashi kerak. vazifalar dagi yozuvniYubor aynan shunday: u hech qachon reject bo'lmaydi.
Bu ataylab. Oddiy async funksiyadagi xato ko'pincha jimgina yo'qoladi — konsolda bitta qizil qator, ekranda hech narsa. Action'da React uni ko'rinadigan qiladi. Kutilmagan xato (server yiqildi) uchun to'g'ri joy — error boundary: Error boundary darsida uni yozamiz va Action xatosini ushlaymiz.
5.2 Kutilgan xato — qiymat
"Ism kerak", "bu stol band" — bular kutilgan javob, ilovani yiqitmasligi kerak. Ularni throw emas, qaytarish kerak. Oddiy Action natija qaytara olmaydi — <form action> qaytgan qiymatni e'tiborsiz qoldiradi. Shuning uchun:
- kichik holatda —
try/catchva state (lekincatchdagi setter ham Action tugagach chiziladi); - formada —
useActionState: Action'ning qaytgan qiymati — yangi state (keyingi dars).
vazifalar dagi yozuvniYubor ham shunday: u hech qachon reject bo'lmaydi va { ok: false, xabar } qaytaradi. Buni «Vazifalar qadami» bo'limida ko'ramiz.
| Xato turi | Misol | Qanday |
|---|---|---|
| kutilgan | "Ism kerak", 409 band | qiymat qaytarish (useActionState) |
| kutilmagan | 500, tarmoq uzildi, kodda xato | throw → error boundary |
6. Action'ni nomlash va props
React hujjati va kutubxonalar Action funksiyalarini …Action bilan nomlaydi: submitAction, updateNameAction. Komponent tashqaridan funksiya olsa va uni transition ichida chaqirsa — prop nomi ham action bilan tugaydi:
// Tugma bosilganda Action'ni o'zi transition ichida chaqiradi
function SaveButton({ saveAction, children }) {
const [isPending, startTransition] = useTransition();
return (
<button
disabled={isPending}
onClick={() => startTransition(() => saveAction())}
>
{isPending ? "Saqlanmoqda…" : children}
</button>
);
}Nom — kelishuv: saveAction ni ko'rgan dasturchi "bu transition ichida chaqiriladi, ichidagi setterlar Action tugagach chiziladi" deb biladi. Oddiy onClick prop'i esa bunday va'da bermaydi. Komponent API'sini loyihalash darsida bunday nomlarga qaytamiz.
7. Vazifalar qadami: yozuvlar — Action (1-qism)
7.1 Muammo: v7 dagi yozuv
vazifalar v7 da katak bosilganda shunday bo'lardi: flushSync bilan ro'yxat darhol yangilanadi, keyin serverga so'rov. Server rad etsa — oldingi ro'yxat qaytariladi. Bitta yozuvda bu ishlaydi. Ikki yozuv bir vaqtda bo'lsa-chi? Kanonni qurishda o'lchandi (07-poyga-v7.txt, soxta server, 1-katak rad etiladi, 2-katak tasdiqlanadi):
ekran ketma-ketligi (1-katak, 2-katak): -- → x- → xx → -- → -xIkki katak ketma-ket bosildi (xx). Birinchisi rad etildi va v7 "oldingi ro'yxat" ni qaytardi — u ikkinchi bosishdan oldingi edi. Ikkinchi katak ham ~400 ms yo'qoldi (--) va server javobidan keyin qaytdi. Foydalanuvchi uchun bu — "men belgilagan narsa o'chib qoldi".
Uch darsda shuni tuzatamiz: bugun — yozuv Action bo'ladi, keyingi darsda — forma, useOptimistic da — ekran va commit. Kanonda uchala dars — bitta commit (refactor/actions-optimistik branch'i).
7.2 fondaYoz — hodisadan Action
Katak, tahrir, o'chirish va import — oddiy hodisa ishlovchilari. Ular Action'ni o'zlari boshlaydi (App.tsx, kanondan aynan):
// Hodisa ishlovchisidan (katak, tahrir, o'chirish, import):
// action'ni o'zimiz boshlaymiz. Async funksiya startTransition
// ichida — React 19
function fondaYoz(
amal: VazifaAmali,
serverda: () => Promise<VazifaAmali>,
) {
startTransition(async () => {
await yozuv(amal, serverda);
});
}startTransition — hook'siz versiyasi, react dan (useTransition dagi "hooksiz" bo'limi). isPending bu yerda kerak emas — katak darhol belgilanadi, kutish ko'rsatilmaydi. yozuv funksiyasining ichi — useOptimistic darsida.
E'tibor bering: serverda endi Promise<VazifaAmali> qaytaradi — server javobidan yasalgan amal. Masalan, yangi vazifa id'si endi serverdan keladi.
7.3 yozuvniYubor — tasdiq yana transition'da
Server qismi — server-sinxron.ts. Kod kanondan aynan:
/** yozuvniYubor natijasi: rad etilsa — e'lon matni */
export type YozuvNatijasi =
| { readonly ok: true }
| { readonly ok: false; readonly xabar: string };
export async function yozuvniYubor(
serverda: () => Promise<VazifaAmali>,
s: Sozlagichlar,
songgi: () => Vazifalar,
): Promise<YozuvNatijasi> {
const x = s.xojalik.current;
x.pult?.abort(); // yo'ldagi solishtirish endi eskirgan
x.kutilmoqda++;
let oxirgi = songgi();
try {
const tasdiq = await serverda();
oxirgi = vazifalarReducer(
boshlangichHolat(songgi()),
tasdiq,
).vazifalar;
// await'dan keyingi yangilanish yana startTransition ichida — u
// action bilan BIRGA tugaydi: optimistik qatlam olinganda asosiy
// holat allaqachon yangi (ekran bir zum eskisiga sakramaydi)
startTransition(() => {
s.dispatch(tasdiq);
});
tablargaYubor(oxirgi);
return { ok: true };
} catch (xato) {
return { ok: false, xabar: `Saqlanmadi: ${xatoMatni(xato)}` };
} finally {
x.kutilmoqda--;
// oxirgisi tugagach — server bilan solishtirish
void sinxronla(oxirgi, s);
}
}Kanondagi JSDoc izohi bu yerda tushirib qoldirildi, oxirgi qatordagi izoh esa telefonga sig'ishi uchun yuqoriga ko'chirildi (u useOptimistic haqida — useOptimistic da o'qiymiz). Bugungi darsning uch qoidasi shu funksiyada:
awaitdan keyin —startTransition.s.dispatch(tasdiq)Action bilan birga tugaydi. O'ralmasa, u shoshilinch bo'lib alohida chizilardi — «awaitdan keyin — yanastartTransition» bo'limidagi tuzoq.- Reject yo'q. Rad etilish —
{ ok: false, xabar }qiymati,throwemas. Rad etilgan yozuv kutilgan holat, ilovani yiqitmasligi kerak («Kutilgan xato — qiymat» bo'limi). songgi()— funksiya, qiymat emas.awaitdan keyin closure'dagi ro'yxat eskirgan bo'lishi mumkin: yozuv yo'lda ekan, boshqa tab yoki boshqa yozuv ro'yxatni o'zgartirgan.songgiApp'dagi ref'dan eng so'nggisini oladi (useRef I).
v7 dagi royxatniQoy(oldingi, s) — "oldingi ro'yxatni qaytarish" — yo'qoldi. Rad etilganda nima bo'ladi? Hech narsa: React o'zi qaytaradi. Qanday — useOptimistic darsining asosiy mavzusi.
7.4 flushSync ketdi, fokus qoldi
v7 da flushSync(() => dispatch(amal)) dan keyin darhol focus() chaqirilardi: DOM yangilangan bo'lishi kerak edi (useRef II). Action ichidagi yangilanishni flushSync bilan chizib bo'lmaydi — u transition. Kanondagi yechim: fokus rejalashtiriladi va keyingi commit'dan keyin useLayoutEffect da qo'yiladi (fokusniRejala). Kodini useOptimistic darsida to'liq o'qiymiz.
8. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
| "Saqlanmoqda…" hech qachon ko'rinmaydi | setter Action ichida, await dan oldin |
isPending, useFormStatus yoki useOptimistic |
| natija Action tugashidan oldin, alohida chiziladi | await dan keyingi setter o'ralmagan |
startTransition(() => set…) |
oq ekran, Uncaught Error |
Action throw qildi, error boundary yo'q |
kutilgani — qiymat; kutilmagani — Error boundary |
| xato bo'lsa ham maydon bo'shadi | Action qiymat qaytardi — React uni muvaffaqiyat deb biladi | useActionState + defaultValue (useActionState) |
| controlled maydon tozalanmadi | reset faqat uncontrolled'ga tegadi | Action ichida set…("") |
requestFormReset was called outside a transition or action |
oddiy onClick da chaqirilgan |
startTransition ichiga |
| eski javob yangisini bosib ketdi | Action'lar parallel, javoblar aralash tartibda | useActionState (navbat) yoki so'nggi so'rovni tekshirish |
9. Mashqlar
Mashqlar kurs/mashqlar/18/05-actions/ da. Har yechimni «Ishga tushir» bilan sinang.
1-mashq (oson): nima ko'rinadi?
Action shunday:
startTransition(async () => {
setStatus("Yuborilmoqda…");
await sendOrder(); // 300 ms
startTransition(() => setStatus("Yuborildi"));
});- Bosilgandan 100 ms keyin
statusekranda "Yuborilmoqda…" mi? - Bosilgandan 100 ms keyin
isPendingqanday? - Forma Action'i muvaffaqiyatli tugasa, controlled maydon bo'shaydimi?
requestFormResetni oddiyonClickichida (transition'siz) chaqirsa bo'ladimi?
Yechim
- yo'q —
setStatus("Yuborilmoqda…")Action ichida. Action yangilanishlari u tugagach birga chiziladi, "Yuborilmoqda…" ning ustidan "Yuborildi" yoziladi («"Saqlanmoqda…" ko'rinmadi» bo'limi). - true —
isPendingbosish paytidagi shoshilinch renderdatruebo'ladi va Action tugaguncha shunday turadi. - yo'q — reset faqat uncontrolled maydonlarga tegadi; controlled maydon qiymati state'da.
- yo'q — konsolda
requestFormReset was called outside a transition or actionchiqadi. Dev'da forma baribir tozalanadi, lekin reset Action'dan ajralib, alohida chiziladi.
2-mashq (o'rta): ikki tugma — ikki Action
«Bahor» buyurtma formasi: taom nomi (name="dish") va ikki tugma. «Savatga» — addToCart Action'i: "savat: Osh" qatorini ro'yxatga qo'shadi. «Hoziroq buyurtma» — orderNow Action'i: "buyurtma: Osh" qatorini qo'shadi. Ikkala Action ham FormData dan taom nomini oladi. onClick va preventDefault ishlatmang. Ishora: «formAction: bitta forma — ikki Action» bo'limi.
Yechim
import { useState } from "react";
export default function App() {
const [log, setLog] = useState([]);
function addToCart(formData) {
setLog((l) => [...l, `savat: ${formData.get("dish")}`]);
}
function orderNow(formData) {
setLog((l) => [...l, `buyurtma: ${formData.get("dish")}`]);
}
return (
<form action={addToCart}>
<label>
Taom <input name="dish" />
</label>
<button>Savatga</button>{" "}
<button formAction={orderNow}>Hoziroq buyurtma</button>
<ul>
{log.map((line, i) => (
<li key={i}>{line}</li>
))}
</ul>
</form>
);
}Ekranda:
Taom Savatga Hoziroq buyurtma
savat: Osh
buyurtma: Manti«Savatga» — formaning o'z action i, «Hoziroq buyurtma» — tugmaning formAction i. Har yuborishdan keyin maydon tozalanadi (uncontrolled), shuning uchun "Manti" ni yangidan yozamiz. setLog da updater funksiya — State II: bir nechta Action ketma-ket kelsa ham hech biri yo'qolmaydi.
3-mashq (qiyin): "Saqlanmoqda…" va xato
Narxni saqlash tugmasi. Boshlang'ich kod ishlaydi, lekin ikki muammo bor: "Saqlanmoqda…" hech qachon ko'rinmaydi va server rad etsa, ilova yiqiladi. Tuzating:
- Kutish paytida
<p>da "Saqlanmoqda…" chiqsin (isPendingbilan). - Server rad etsa, ilova yiqilmasin:
<p role="alert">da xato matni chiqsin. Ishora:try/catchAction ichida, xatoni state'ga yozing.awaitdan keyingi setter —startTransitionichida. savePriceni o'zgartirmang.
import { useState, useTransition } from "react";
function savePrice(price) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (price > 100000) reject(new Error("Narx juda katta"));
else resolve(price);
}, 200);
});
}
export default function App() {
const [message, setMessage] = useState("");
const [, startTransition] = useTransition();
function handleClick() {
startTransition(async () => {
setMessage("Saqlanmoqda…");
const price = await savePrice(350000);
startTransition(() => setMessage(`Saqlandi: ${price}`));
});
}
return (
<div>
<button onClick={handleClick}>Saqlash</button>
<p>{message}</p>
</div>
);
}Konsolda:
Uncaught Error: Narx juda kattaYechim
import { useState, useTransition } from "react";
function savePrice(price) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (price > 100000) reject(new Error("Narx juda katta"));
else resolve(price);
}, 200);
});
}
export default function App() {
const [message, setMessage] = useState("");
const [error, setError] = useState(null);
const [isPending, startTransition] = useTransition();
function handleClick() {
startTransition(async () => {
setError(null);
try {
const price = await savePrice(350000);
startTransition(() => setMessage(`Saqlandi: ${price}`));
} catch (err) {
startTransition(() => setError(err.message));
}
});
}
return (
<div>
<button onClick={handleClick} disabled={isPending}>
Saqlash
</button>
<p>{isPending ? "Saqlanmoqda…" : message}</p>
{error && <p role="alert">{error}</p>}
</div>
);
}Ekranda:
Saqlash
Narx juda katta"Saqlanmoqda…" endi isPending dan — u shoshilinch renderda chiziladi (ekran("Saqlanmoqda…") 60 ms da tekshiradi). Xato catch da qiymatga aylandi. Action reject bo'lmaydi va React uni error boundary'ga yubormaydi. setError ham await dan keyin, shuning uchun u ham startTransition ichida. 350000 ni 35000 ga almashtirsangiz — "Saqlandi: 35000". Bunday holatda useActionState qisqaroq — keyingi darsda.
4-mashq: Vazifalar qadami
refactor/actions-optimistik branch'ini oching. server-sinxron.ts dagi yozuvniYubor ni «Vazifalar qadami» bo'limidagidek o'zgartiring (serverda — Promise<VazifaAmali>, tasdiq — startTransition ichida, natija — YozuvNatijasi). App'da fondaYoz ni qo'shing. Commit — uchinchi qismdan keyin (useOptimistic).
Yechim
Tekshiruv ro'yxati:
yozuvniYuborhech qachon reject bo'lmaydi:catch—{ ok: false, xabar },finally—kutilmoqda--va solishtirish.await serverda()dan keyingis.dispatch(tasdiq)—startTransition(() => …)ichida.fondaYoz—startTransition(async () => { await yozuv(amal, serverda); });yozuvni useOptimistic darsida yozasiz, hozirchatscuni topmaydi — bu kutilgan.- Hali commit qilmang: kanonda #05–#07 — bitta commit.
10. Real ishda
- React hujjati va kutubxonalar — yangi kodda "kutish" holati endi
isPendingdan,isLoadingstate'idan emas. Kod ko'rigida qo'ldasetIsSaving(true)/finallyni ko'rsangiz — Action'ga aylantirishni taklif qilish mumkin. - Next.js Server Actions —
<form action={serverFunction}>: Action serverda bajariladi, React esa bugungi qoidalar bilan uni kutadi va formani tozalaydi (Server Actions I). Bugungi dars — ularning brauzer tomoni. - TanStack Query dagi
useMutation—isPending, xato va qayta urinish bilan yozuvlar. Action g'oyasi unga juda yaqin (TanStack Query III). - Intervyu savollari: "React 19 da Action nima?", "
<form action>nima qiladi va qachon formani tozalaydi?", "nega Action ichidagisetStatedarhol ko'rinmaydi?", "requestFormResetvaform.reset()farqi?".
Xulosa
- Action — transition ichida chaqirilgan funksiya (ko'pincha
async).isPendingu tugagunchatrue. - Action ichidagi setterlar u tugagach birga chiziladi — oraliq "Saqlanmoqda…" ko'rinmaydi.
awaitdan keyingi setter — yanastartTransition. <form action>vaformAction— Action'ning tayyor yo'li:FormData, transition va muvaffaqiyatda uncontrolled maydonlarni reset.requestFormReset(form)— faqat Action ichida; reset Action natijasi bilan birga chiziladi.- Action'dagi
throw— error boundary'ga; kutilgan xato — qiymat. vazifalar:fondaYoz— hodisadan Action,yozuvniYubor— reject'siz, tasdiqstartTransitionichida (1-qism, commit — #07).
Keyingi dars: useActionState va useFormStatus — Action natijasi va navbati, forma ichidagi tugma o'z formasining holatini props'siz qanday bilishi.
Manbalar
- React:
useTransition— "Perform non-blocking updates with Actions" — react.dev/reference/react/useTransition (2026-10 holati, React 19.3) - React:
<form>— react.dev/reference/react-dom/components/form - React:
requestFormReset— react.dev/reference/react-dom/requestFormReset - React blog: "React v19" (2024-12-05) — Actions — react.dev/blog/2024/12/05/react-19
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!