Mundarija (30)
- Bu darsda
- 1. Nega bu kerak?
- 2. Birinchi Server Action
- 2.1 "use server" fayli
- 2.2 Ikkita yozish usuli
- 2.3 Biz topdik: faqat async
- 3. Pardaning orqasi: nima yuboriladi?
- 3.1 Brauzerda funksiya yo'q
- 3.2 Biz o'lchadik: JS bilan va JS'siz
- 3.3 Progressive enhancement
- 4. Action'ni chaqirish yo'llari
- 4.1 Forma, tugma va hodisa
- 4.2 Qo'shimcha argument: bind
- 4.3 Natija oynasida: React form action
- 5. Mutatsiyadan keyin
- 5.1 Keshni yangilash
- 5.2 redirect — oxirida va try dan tashqarida
- 6. Kanon: «Aloqa» formasi
- 6.1 Xabar qayerga ketadi?
- 6.2 Action'ning skeleti
- 7. Portfolio qadami: forma serverga
- 8. Ko'p uchraydigan xatolar
- 9. Mashqlar
- 1-mashq (oson): bu qayerda ishlaydi?
- 2-mashq (o'rta): ikki tugma, ikki amal
- 3-mashq (qiyin): bind va ishonchsiz argument
- 4-mashq: Portfolio qadami
- 10. Real ishda
- Xulosa
- Manbalar
Next.js Server Actions: "use server" va JavaScript'siz ishlaydigan forma
Qisqacha: Server Action —
"use server"bilan belgilangan async funksiya. U serverda ishlaydi, lekin uni client'dan oddiy funksiya kabi chaqirasiz — eng ko'p<form action={xabarYubor}>orqali. Next.js build vaqtida funksiya tanasini brauzer to'plamidan olib tashlaydi va o'rniga "shu ID'li action'ni POST qil" degan havolani qo'yadi. Forma JavaScript yuklanmasdan ham ishlaydi: brauzer oddiy HTML forma kabi POST yuboradi (progressive enhancement). Action ichidaFormDatao'qiladi, ma'lumot saqlanadi, keyin kesh yangilanadi yokiredirect()qilinadi. Har Server Action — ochiq POST manzil, shuning uchun tekshiruvlar action ichida bo'lishi shart.
Bu darsda
"use server"faylida Server Action yozasiz va uni formaga ulaysiz.- Brauzer qanday so'rov yuborishini haqiqiy o'lchov bilan ko'rasiz:
Next-Actionsarlavhasi va JS'siz formadagi yashirin maydonlar. - Action'ni forma, tugma (
formAction) va hodisa ichidan chaqirish yo'llarini ajratasiz. - Mutatsiyadan keyin
revalidatePath,updateTagvaredirectni to'g'ri tartibda ishlatasiz. portfolioning «Aloqa» sahifasiga Server Action bilan forma qo'shasiz (holat 23 ning birinchi qismi).
Oldin bilishingiz kerak: Actions: async transitionlar va form action, Serverda ma'lumot olish, Cache Components II, FormData, Client Components va "use client".
1. Nega bu kerak?
v1 portfolio'dagi aloqa formasini eslang (04 va 09-qismlar). U chiroyli edi: maydonlar, tekshiruv, yuborilmoqda holati. Lekin bitta muammo bor edi — xabar hech qayerga ketmasdi. GitHub Pages'da server yo'q, forma faqat brauzerda "Rahmat" deb qo'yardi.
Xabarni haqiqatan qabul qilish uchun server kerak. Odatda bu ikki qismli ish: backend'da API manzil (POST /api/xabar) yozasiz, frontend'da fetch bilan unga yuborasiz, javobni tekshirasiz, xatolarni ko'rsatasiz. Ikki fayl, ikki til (JSON formati, URL, metod), ikki joyda turlar.
Next.js'da qisqaroq yo'l bor. Serverda ishlaydigan funksiya yozasiz va uni formaga to'g'ridan berasiz. Qolganini — POST so'rov, ma'lumotni uzatish, javobni qaytarish — Next.js o'zi qiladi.
Hayotiy o'xshatish: pochta qutisi. Siz xatni qutiga tashlaysiz — u qanday yetib borishi, qaysi mashinada ketishi sizning ishingiz emas. Manzilni bilsangiz yetarli. Server Action — formangiz uchun shunday "pochta qutisi".
18-qismda React 19 Actions bilan tanishgansiz: <form action={async (formData) => …}>. U yerda funksiya brauzerda ishlardi. Next.js'da aynan o'sha action prop'iga serverdagi funksiya beriladi.
2. Birinchi Server Action
2.1 "use server" fayli
Eng sodda variant — alohida fayl, birinchi qatorida "use server". Fayldagi har bir export qilingan async funksiya — Server Action:
// app/(sayt)/aloqa/_amal/xabarYubor.ts — soddalashtirilgan
"use server";
export async function xabarYubor(forma: FormData) {
const ism = String(forma.get("ism") ?? "");
const xabar = String(forma.get("xabar") ?? "");
console.log("Yangi xabar:", ism, xabar.length, "belgi");
}_amal papkasi _ bilan boshlangani uchun marshrut emas — u faqat kodni saqlaydi (Route groups va private papkalar).
Formada:
// app/(sayt)/aloqa/page.tsx — Server Component
import { xabarYubor } from "./_amal/xabarYubor";
export default function AloqaSahifasi() {
return (
<form action={xabarYubor}>
<label htmlFor="ism">Ismingiz</label>
<input id="ism" name="ism" required />
<label htmlFor="xabar">Xabar</label>
<textarea id="xabar" name="xabar" required />
<button type="submit">Yuborish</button>
</form>
);
}name atributlari muhim: forma.get("ism") aynan shu nom bilan o'qiydi (FormData). console.log brauzer konsolida emas, server terminalida chiqadi — funksiya serverda ishlaydi.
2.2 Ikkita yozish usuli
"use server" ni ikki joyga yozish mumkin:
| Joy | Misol | Qachon |
|---|---|---|
| Fayl boshida | _amal/xabarYubor.ts |
Odatiy; client komponentlar ham import qila oladi |
| Funksiya ichida | Server Component ichidagi async function |
Faqat Server Component'da, kichik misollar |
Ikkinchisi — "inline" action:
export default function Sahifa() {
async function salomla(forma: FormData) {
"use server";
console.log("Salom,", forma.get("ism"));
}
return <form action={salomla}>{/* … */}</form>;
}Client komponent fayli ("use client") ichida inline "use server" yozib bo'lmaydi — u holda action alohida "use server" fayldan import qilinadi. Kanon birinchi yo'lni tanladi: action alohida faylda, forma — client komponentda (keyingi darsda useActionState uchun).
2.3 Biz topdik: faqat async
"use server" fayldagi har export — Server Action. Sinxron funksiya eksport qilinsa nima bo'ladi? Biz kanon xabarYubor.ts oxiriga oddiy yordamchi funksiya qo'shib build qildik:
export function maydonlarSoni() {
return MAYDONLAR.length;
}Error: Turbopack build failed with 1 error:
./src/app/(sayt)/aloqa/_amal/xabarYubor.ts:50:17
Error: Server Actions must be async functions.Tarjimasi: "Server Action'lar async funksiya bo'lishi shart". Next.js har eksportni "client'dan chaqiriladigan manzil" deb ko'radi, va tarmoq orqali chaqiruv doim asinxron. Yordamchi funksiyalar, konstantalar, turlar — alohida faylda turadi (kanonda sxema.ts). Turni eksport qilish mumkin (export type kompilyatsiyada o'chib ketadi).
Tekshirib ko'ring:
"use server"faylidaexport const LIMIT = 3;yozish mumkinmi?
Javob
Yo'q. "use server" fayldan faqat async funksiyalar eksport qilinadi — konstanta ham Server Action deb tekshiriladi va build xato beradi. LIMIT ni boshqa faylga (masalan sozlama.ts) qo'ying va ikkala joyda import qiling. Eksport qilinmagan ichki konstanta esa mumkin — kanonda const MAYDONLAR = […] aynan shunday.
3. Pardaning orqasi: nima yuboriladi?
3.1 Brauzerda funksiya yo'q
Build vaqtida Next.js "use server" funksiyaning tanasini client to'plamidan olib tashlaydi. Brauzerga faqat havola boradi: action ID (shifrlangan identifikator) va "shu ID'ni serverga POST qil" degan kichik dispetcher. Funksiya kodi, uning importlari (node:fs, baza klienti), sirlar — hammasi serverda qoladi.
3.2 Biz o'lchadik: JS bilan va JS'siz
Biz kanon holatini (23–24) next build + next start bilan ishga tushirib, «Aloqa» formasini headless Chrome'da ikki marta to'ldirdik — JavaScript yoqilgan va o'chiq holda. Formaning HTML'i, brauzer yuborgan POST va natija:
JS yoqilgan: form action= | yashirin: $ACTION_REF_1, $ACTION_1:0, $ACTION_1:1, $ACTION_KEY
POST /aloqa content-type=multipart/form-data next-action=60fd8924…(42 belgi)
URL: /aloqa | natija: Rahmat, Aziz! Xabaringiz qabul qilindi — odatda bir kun ichida javob b
JS o'chiq: form action= | yashirin: $ACTION_REF_1, $ACTION_1:0, $ACTION_1:1, $ACTION_KEY
POST /aloqa content-type=multipart/form-data next-action=yo'q
URL: /aloqa | natija: Rahmat, Malika! Xabaringiz qabul qilindi — odatda bir kun ichida javobAction ID'ni 8 belgigacha qisqartirdik — u har build'da boshqa. Nimani ko'ramiz:
| JS yoqilgan | JS o'chiq | |
|---|---|---|
| Kim yuboradi | React (fetch) |
Brauzerning o'zi (oddiy forma) |
| Manzil | Joriy sahifa: POST /aloqa |
Xuddi shu |
| Action qanday aniqlanadi | Next-Action sarlavhasi |
Yashirin $ACTION_… maydonlari |
| Javob | RSC payload — sahifa joyida yangilanadi | Butun HTML sahifa |
| Natija | "Rahmat, Aziz!" | "Rahmat, Malika!" |
action= bo'sh — forma joriy manzilga (/aloqa) yuboriladi. Next.js server HTML'ga to'rtta yashirin maydon qo'shgan: ular JavaScript bo'lmaganda ham "qaysi action" ekanini serverga aytadi. Shuning uchun forma JS'siz ham ishladi.
Kanonning o'z o'lchovi ham xuddi shu (natijalar/23-forma.txt):
3) JS'siz: POST 200 | Rahmat, Malika! Xabaringiz qabul qilindi — odatda bir kun ic
yashirin maydonlar (JS'siz forma uchun): $ACTION_REF_1, $ACTION_1:0, $ACTION_1:1, $ACTION_KEYsequenceDiagram
participant B as Brauzer
participant N as Next.js server
B->>N: POST /aloqa (FormData + Next-Action: id)
N->>N: xabarYubor(forma) ishlaydi
N-->>B: action natijasi + yangilangan sahifa (RSC)
Note over B: JS o'chiq bo'lsa: oddiy POST, javob — butun HTMLDiagrammadagi asosiy narsa: bitta so'rov. Next.js hujjati bo'yicha action natijasi va qayta chizilgan sahifa bitta javobda keladi — alohida "keyin ma'lumotni qayta ol" so'rovi yo'q.
3.3 Progressive enhancement
Progressive enhancement (bosqichma-bosqich yaxshilash) — sahifa avval eng oddiy vositalar (HTML) bilan ishlaydi, JavaScript esa uni qulayroq qiladi, lekin shart emas. JS yuklanmagan bo'lsa (sekin internet, eski telefon, JS o'chirilgan, xato), forma baribir yuboriladi.
Aziz sekin internetda telefondan saytingizni ochdi. Sahifaning HTML'i keldi, JS to'plami hali yuklanmoqda. U formani to'ldirib «Yuborish» ni bosdi. Oddiy React formasida (onSubmit + fetch) hech narsa bo'lmasdi — hodisa ishlovchisi hali yo'q. Server Action formasi esa ishlaydi. Bu nazariya emas — biz yuqorida JS o'chiq holatda "Rahmat, Malika!" ni oldik.
Bu imkoniyatni buzish oson — keyingi darsda useOptimistic bilan qanday buzilishini haqiqiy o'lchovda ko'ramiz.
4. Action'ni chaqirish yo'llari
4.1 Forma, tugma va hodisa
| Usul | Kod | JS'siz ishlaydimi |
|---|---|---|
| Forma | <form action={xabarYubor}> |
Ha |
| Tugma | <button formAction={ochir}> |
Ha |
| Hodisa / effekt | startTransition(() => belgila(id)) |
Yo'q |
formAction — bitta formada ikki xil tugma uchun: «Saqlash» va «O'chirish» har biri o'z action'ini chaqiradi (Tugmalar va yuborish).
Hodisa ichidan chaqirish — masalan "yoqdi" tugmasi:
"use client";
import { useTransition } from "react";
import { yoqtir } from "./_amal/yoqtir"; // "use server" fayl
export function YoqtirTugmasi({ postId }: { postId: string }) {
const [kutilmoqda, startTransition] = useTransition();
return (
<button
disabled={kutilmoqda}
onClick={() => startTransition(() => yoqtir(postId))}
>
Yoqdi
</button>
);
}Bu yerda forma yo'q — JS'siz ishlamaydi. Kichik interaktiv amallar uchun qabul qilinadi, lekin asosiy oqim (yuborish, ro'yxatdan o'tish, buyurtma) — forma bilan.
Next.js hujjati bitta nozik xulqni ta'kidlaydi: client bir vaqtda faqat bitta action yuboradi, qolganlari navbatda kutadi. Uchta action'ni Promise.all bilan "parallel" chaqirish ularni tezlashtirmaydi. Parallel ish kerak bo'lsa — uni bitta action ichida qiling.
4.2 Qo'shimcha argument: bind
Action'ga formadan tashqari qiymat kerak bo'lsa (masalan, qaysi post), bind bilan "oldindan" beriladi (call, apply, bind):
// "use server" faylda
export async function izohQosh(postId: string, forma: FormData) {
// …
}
// Server Component'da
const izohQoshPostga = izohQosh.bind(null, post.slug);
return <form action={izohQoshPostga}>{/* … */}</form>;bind qilingan qiymat ham JS'siz formada ishlaydi (Next.js uni yashirin maydonlarga qo'yadi). Lekin u brauzerdan keladi — hujumchi uni o'zgartira oladi. postId ga ishonmang, serverda tekshiring (Server Actions xavfsizligi).
4.3 Natija oynasida: React form action
Natija oynasida server yo'q, lekin React 19'ning <form action> mexanizmi aynan o'sha. Server Action o'rnida — oddiy async funksiya (200 ms "tarmoq"). Kodni ishga tushiring:
import { useState } from "react";
const wait = (ms: number) => new Promise((r) => setTimeout(r, ms));
export default function App() {
const [result, setResult] = useState("");
// Next.js'da bu "use server" fayldagi funksiya bo'lardi
async function sendMessage(formData: FormData) {
const name = String(formData.get("ism") ?? "");
const text = String(formData.get("xabar") ?? "");
console.log("ism:", name);
console.log("xabar uzunligi:", text.length);
await wait(200);
setResult(`Rahmat, ${name}!`);
}
return (
<form action={sendMessage}>
<label>
Ismingiz <input name="ism" />
</label>
<label>
Xabar <textarea name="xabar" />
</label>
<button type="submit">Yuborish</button>
<p role="status">{result}</p>
</form>
);
}Konsolda:
ism: Aziz
xabar uzunligi: 23Ekranda:
Ismingiz Xabar Yuborish
Rahmat, Aziz!React action tugagach formani tozalaydi (inputlar bo'shaydi) — buni React 19 o'zi qiladi. Haqiqiy Next.js'da farq bitta: sendMessage serverda ishlaydi, console.log terminalda chiqadi, setResult o'rniga esa action natija qaytaradi (keyingi dars).
Tekshirib ko'ring: natija oynasidagi forma JavaScript o'chiq bo'lsa ishlaydimi?
Javob
Yo'q. Bu yerda sendMessage — brauzerdagi funksiya, uni React JS orqali chaqiradi. JS bo'lmasa, forma qayoqqa yuborishni bilmaydi. Next.js'dagi Server Action esa server manzilini va yashirin maydonlarni HTML'ga yozadi — shuning uchun JS'siz ham ishlaydi.
5. Mutatsiyadan keyin
5.1 Keshni yangilash
Action ma'lumotni o'zgartirdi — endi sahifa yangi ma'lumotni ko'rsatishi kerak. Cache Components II dagi vositalar shu yerda ishlatiladi:
"use server";
import { updateTag } from "next/cache";
export async function postQosh(forma: FormData) {
await postniSaqla(forma); // bazaga — 26-qismdan
updateTag("postlar"); // o'zi darhol ko'radi
}Next.js updateTag, revalidatePath yoki refresh() chaqirilgan action'dan keyin joriy sahifani serverda qayta chizadi va o'sha javobning ichida yuboradi. Alohida qayta yuklash kerak emas.
5.2 redirect — oxirida va try dan tashqarida
Ko'pincha saqlagandan keyin boshqa sahifaga o'tiladi: yangi post sahifasiga yoki "rahmat" sahifasiga.
"use server";
import { redirect } from "next/navigation";
import { updateTag } from "next/cache";
export async function postQosh(forma: FormData) {
let slug: string;
try {
slug = await postniSaqla(forma);
} catch {
return { xato: "Saqlab bo'lmadi" };
}
updateTag("postlar"); // avval kesh
// keyin o'tish — bu qatordan keyin hech narsa ishlamaydi
redirect(`/blog/${slug}`);
}Ikki qoida:
redirect()xato tashlash orqali ishlaydi. Unitryichida chaqirsangiz,catchuni ushlab oladi va o'tish bo'lmaydi. Serverda ma'lumot olish darsidagi "kengcatchNext.js signalini yutadi" saboqning yana bir ko'rinishi.- Kesh yangilash
redirectdan oldin: undan keyingi kod ishlamaydi.
JS'siz formada redirect oddiy HTTP 303 yo'naltirish bo'lib ishlaydi — progressive enhancement saqlanadi.
6. Kanon: «Aloqa» formasi
Kanon «Aloqa» sahifasiga v1 formani qaytardi — endi haqiqiy server bilan. Maydonlar v1 dagidek: ism, email, mavzu (radio: «Ish taklifi» / «Savol»), xabar va bot'lar uchun yashirin "asal idish" maydoni. Fayllar:
| Fayl | Vazifa | Dars |
|---|---|---|
aloqa/_amal/xabarYubor.ts |
"use server" — Server Action |
shu dars |
aloqa/_amal/sxema.ts |
Zod sxemasi va FormaHolati turi |
N-22 |
aloqa/_komponentlar/AloqaFormasi.tsx |
Client: useActionState, useFormStatus |
N-22 |
src/malumot/xabarlar.ts |
Xabarni saqlash (server-only) |
shu dars |
src/malumot/tezlik.ts |
Tezlik cheklovi | N-23 |
6.1 Xabar qayerga ketadi?
Halol javob: hozircha uzoqqa emas. Kanon xabarlar.ts:
import "server-only";
import { appendFile, mkdir } from "node:fs/promises";
import path from "node:path";
import type { Xabar } from "@/app/(sayt)/aloqa/_amal/sxema";
// Xabar qayerga ketadi? Backend 24+ qismlarda. Hozir: dev —
// lokal fayl (.data/, git'ga tushmaydi); prod — faqat log
// (shaxsiy ma'lumotsiz). Resend, Telegram bot, Vercel KV —
// hujjat bo'yicha, kalit talab qiladi.
export async function xabarniSaqla(x: Xabar): Promise<void> {
if (process.env.NODE_ENV !== "production") {
const papka = path.join(process.cwd(), ".data");
await mkdir(papka, { recursive: true });
await appendFile(
path.join(papka, "xabarlar.jsonl"),
JSON.stringify({ ...x, vaqt: new Date().toISOString() }) + "\n",
);
return;
}
console.info(
JSON.stringify({
tur: "aloqa-xabari",
mavzu: x.mavzu,
uzunlik: x.xabar.length,
}),
);
}Kanon izohi telefonga sig'ishi uchun bo'lindi.
- Dev'da —
.data/xabarlar.jsonlfayliga, har xabar bitta JSON qator (JSON Lines)..datapapkasi.gitignoreda — shaxsiy ma'lumot git'ga tushmaydi. - Production'da — faqat log: mavzu va uzunlik, ism va email yo'q. Serverless platformada (Vercel) fayl tizimiga yozib bo'lmaydi, loglarga esa shaxsiy ma'lumot yozilmasligi kerak.
Real saytda xabar emailga (Resend kabi xizmat), Telegram botga yoki bazaga ketadi. Ularning hammasi kalit (API key) talab qiladi — kanonda hisob ochilmagan, shuning uchun ular faqat hujjat bo'yicha tilga olinadi. Haqiqiy saqlash — backend qismlarida (25+).
6.2 Action'ning skeleti
Kanon xabarYubor to'liq ko'rinishi keyingi ikki darsda bo'lak-bo'lak ochiladi (validatsiya, holat, xavfsizlik). Bugungi asosiy shakli:
"use server";
// Server Action (N-21…N-23). Har "use server" funksiya — ochiq
// POST endpoint: kim xohlasa chaqira oladi, shuning uchun hamma
// tekshiruv shu yerda.
export async function xabarYubor(
_oldingi: FormaHolati,
forma: FormData,
): Promise<FormaHolati> {
// 1) maydonlarni o'qish — shu dars
// 2) asal idish va tezlik — N-23
// 3) Zod tekshiruvi — N-22
await xabarniSaqla(natija.data); // 4) saqlash — shu dars
return { holat: "yuborildi", ism: natija.data.ism };
}E'tibor bering: kanon imzosida ikkita parametr — _oldingi (oldingi holat) va forma. Bu useActionState talabi, uni keyingi darsda ochamiz. Pastki chiziq (_oldingi) — "parametr bor, lekin ishlatilmaydi" degan kelishuv.
7. Portfolio qadami: forma serverga
Bu dars, Server Actions II va Server Actions xavfsizligi — portfolio ning bitta holati (23). Commit — uchinchisida. Hali commit qilmang.
Bugun:
src/malumot/xabarlar.ts— yuqoridagi kod..gitignorega.dataqatori.aloqa/_amal/xabarYubor.ts—"use server", hozircha sodda shakl (2.1 dagidek): maydonlarni o'qib,xabarniSaqlaga beradi.aloqa/page.tsxdagi formaniaction={xabarYubor}ga ulash.
Tekshiruv: npm run dev, formani yuboring, keyin .data/xabarlar.jsonl ni oching — bitta JSON qator. DevTools → Network: aloqa so'rovi, metod POST, sarlavhalarda Next-Action. Keyin DevTools'da JavaScript'ni o'chirib (Command Menu → "Disable JavaScript") yana yuboring — fayl ikkinchi qatorni olishi kerak.
8. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
Server Actions must be async functions. |
"use server" fayldan sinxron funksiya yoki konstanta eksporti |
Yordamchilarni boshqa faylga |
forma.get("ism") → null |
Inputda name yo'q yoki boshqa |
name="ism" |
console.log brauzerda ko'rinmaydi |
Action serverda ishlaydi | Terminalga qarang |
redirect ishlamadi |
try/catch ichida chaqirilgan |
try dan keyin, oxirida |
| Saqlandi, lekin sahifa eski | Kesh yangilanmagan | updateTag / revalidatePath |
| JS'siz forma ishlamaydi | Action client funksiyaga o'ralgan yoki onSubmit |
action={serverAction} to'g'ridan |
Client faylda inline "use server" xatosi |
Inline faqat Server Component'da | Alohida "use server" fayl |
Production'da ENOENT/EROFS fayl xatosi |
Serverless'da diskka yozib bo'lmaydi | Tashqi saqlash (email, baza) |
9. Mashqlar
Mashqlar kurs/mashqlar/23/21-server-actions/ da. Jonli yechimlarni «Ishga tushir» bilan sinang.
1-mashq (oson): bu qayerda ishlaydi?
"use server"funksiya ichidagiconsole.log— (terminalda)<form action={…}>uchun brauzerdan ketadigan HTTP metod —- JS'siz formada action'ni aniqlaydigan narsa — yashirin
- JS bilan yuborilganda action ID turadigan sarlavha —
Yechim
- serverda — funksiya tanasi brauzerga umuman yuborilmaydi.
- POST — joriy sahifa manziliga.
- maydonlar —
$ACTION_REF_1,$ACTION_KEYva boshqalar. - Next-Action — biz o'lchagan so'rovda 42 belgili ID.
2-mashq (o'rta): ikki tugma, ikki amal
Natija oynasidagi forma misolini o'zgartiring: bitta formada «Qoralama» va «Yuborish» tugmalari bo'lsin. «Qoralama» — formAction={saveDraft}: konsolga qoralama: <xabar> yozadi va ekranda "Qoralama saqlandi" chiqaradi. «Yuborish» — formaning asosiy action i. «Qoralama» ni bosib natijani ko'rsating.
Yechim
import { useState } from "react";
export default function App() {
const [status, setStatus] = useState("");
async function send(formData: FormData) {
console.log("yuborildi:", formData.get("xabar"));
setStatus("Yuborildi");
}
async function saveDraft(formData: FormData) {
console.log("qoralama:", formData.get("xabar"));
setStatus("Qoralama saqlandi");
}
return (
<form action={send}>
<label>
Xabar <textarea name="xabar" />
</label>
<button type="submit" formAction={saveDraft}>
Qoralama
</button>
<button type="submit">Yuborish</button>
<p role="status">{status}</p>
</form>
);
}Konsolda:
qoralama: Ertaga gaplashamizEkranda:
Xabar QoralamaYuborish
Qoralama saqlandiformAction formaning action ini shu tugma uchun almashtiradi. Next.js'da ikkala funksiya Server Action bo'ladi va ikkalasi ham JS'siz ishlaydi — tugmaning HTML formaction atributi orqali. Ekrandagi QoralamaYuborish — ikki tugma orasida bo'shliq yo'q; haqiqiy sahifada CSS ajratadi.
3-mashq (qiyin): bind va ishonchsiz argument
Post sahifasidagi izoh formasi: addComment(postSlug, formData). bind bilan postSlug beriladi. Funksiya serverda postSlug ni ruxsat etilgan ro'yxat (["portfolio-v2", "server-components"]) bo'yicha tekshirsin: noma'lum slug — { ok: false, xato: "post topilmadi" }. Izoh matni bo'sh bo'lsa — { ok: false, xato: "izoh bo'sh" }. To'g'ri bo'lsa — { ok: true }. Funksiyani FormData bilan uch holatda sinang (Node'da ham FormData bor).
Yechim
const POSTS = ["portfolio-v2", "server-components"];
async function addComment(postSlug, formData) {
if (!POSTS.includes(postSlug)) {
return { ok: false, xato: "post topilmadi" };
}
const text = String(formData.get("izoh") ?? "").trim();
if (!text) return { ok: false, xato: "izoh bo'sh" };
return { ok: true };
}
function form(text) {
const fd = new FormData();
fd.set("izoh", text);
return fd;
}
const forPost = addComment.bind(null, "portfolio-v2");
console.log(await forPost(form("Zo'r maqola!")));
console.log(await forPost(form(" ")));
// Hujumchi yashirin maydondagi slug'ni o'zgartirdi:
const forged = addComment.bind(null, "../../etc/passwd");
console.log(await forged(form("salom")));Konsolda:
{ ok: true }
{ ok: false, xato: "izoh bo'sh" }
{ ok: false, xato: 'post topilmadi' }bind dagi qiymat JS'siz formada yashirin maydon bo'lib brauzerga boradi va qaytib keladi — uni o'zgartirish mumkin. Shuning uchun u ham FormData kabi tekshiriladi. Node konsolida apostrofli satr qo'shtirnoq bilan chiqadi ("izoh bo'sh"), qolganlari bittalik bilan.
4-mashq: Portfolio qadami
«Portfolio qadami» bo'limidagi to'rt qadamni bajaring. .data/xabarlar.jsonl da ikki qator (JS bilan va JS'siz) paydo bo'lishini tekshiring, git status da .data ko'rinmasligiga ishonch hosil qiling. Commit hali yo'q.
Yechim
Faylda har qator — {"ism":"…","email":"…","mavzu":"…","xabar":"…","vaqt":"2026-…"} (keyingi darsdagi sxemadan keyin hamma maydonlar to'ladi; hozirgi sodda variantda faqat siz o'qigan maydonlar). Network panelida JS'siz yuborishda Next-Action sarlavhasi bo'lmaydi, lekin so'rov tanasida $ACTION_… maydonlari bor — «Biz o'lchadik» bo'limidagidek.
10. Real ishda
- Formalar — Server Actions'ning asosiy joyi: aloqa, ro'yxatdan o'tish, sharh, buyurtma. Next.js loyihalarida yangi formalar deyarli hammasi shunday yoziladi.
- Admin panellar — CRUD amallari (
yarat,tahrirla,o'chir) action'lar bilan, kesh —updateTagbilan. - Progressive enhancement — davlat xizmatlari, bank saytlari kabi "hamma uchun ishlashi shart" bo'lgan joylarda talab. Server Actions buni deyarli bepul beradi.
- Intervyuda: "Server Action nima va u qanday ishlaydi?", "Server Action va Route Handler farqi?" (Route Handler, Server Action yoki alohida backend?).
Xulosa
- Server Action —
"use server"bilan belgilangan async funksiya; client'dan chaqiriladi, serverda ishlaydi. - Brauzerga funksiya kodi emas, action ID boradi; so'rov — joriy sahifaga
POST(Next-Actionsarlavhasi yoki yashirin maydonlar). <form action>vaformActionJS'siz ham ishlaydi — biz o'lchadik: JS o'chiq holatda ham "Rahmat, Malika!"."use server"fayldan faqat async funksiyalar eksport qilinadi.- Mutatsiyadan keyin: kesh yangilash, keyin
redirect—trydan tashqarida. - Kanon xabarni dev'da
.data/faylga, prod'da faqat shaxsiy ma'lumotsiz logga yozadi.
Keyingi dars: Server Actions II: holat, validatsiya va optimistik UI — Zod bilan tekshiramiz, xatolarni maydonlar yonida ko'rsatamiz va useOptimistic ning yashirin narxini o'lchaymiz.
Manbalar
- Next.js hujjati — Mutating Data 16.4-bob: https://nextjs.org/docs/app/getting-started/mutating-data (2026-10-21 da o'qildi)
- Next.js hujjati — Server Actions and Mutations: https://nextjs.org/docs/app/guides/server-actions
- React hujjati — Server Functions va
"use server": https://react.dev/reference/rsc/use-server - Kanon o'lchovlari:
portfoliov2, holat 23 (natijalar/23-forma.txt,xabarlar.ts); JS bilan/JS'siz so'rovlar va sinxron eksport xatosi — biz ishga tushirdik (next 16.4.0, Chrome 155).
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!