Server Components — nima, Client Components dan farqi
Muammodan boshlaylik
Blog maqolasi sahifasi. Oddiy React ilovada (SPA):
1. Brauzer bo'sh HTML oladi: <div id="root"></div>
2. JavaScript yuklanadi: React + markdown kutubxonasi + kod rangi kutubxonasi (400 KB)
3. React ishga tushadi
4. useEffect → fetch('/api/maqola/42')
5. Javob keladi → markdown HTML ga aylantiriladi
6. Nihoyat — maqola ekranda
Muammolar:
- Foydalanuvchi bo'sh ekran va spinner ni ko'radi
- Brauzer 400 KB JavaScript yuklaydi — maqolani ko'rsatish uchun, garchi maqola interaktiv emas (shunchaki matn)
- Markdown kutubxonasi har bir foydalanuvchining telefonida qayta-qayta ishlaydi — natija esa hamma uchun bir xil
- Google bo'sh
<div id="root">ni ko'radi (HTML kursi, 13-dars) - Ma'lumot uchun alohida API endpoint yozish kerak
React Server Components (RSC) — komponentlarning bir qismini serverda bajarish va brauzerga faqat natijani yuborish.
Server va Client komponentlar
Server Components bilan ilovada ikki turdagi komponent bo'ladi:
// app/maqola/[id]/page.jsx — SERVER komponent (standart holat)
import { db } from '@/lib/db';
import { marked } from 'marked';
import YoqtirishTugmasi from './YoqtirishTugmasi';
export default async function MaqolaSahifasi({ params }) {
const { id } = await params;
const maqola = await db.maqola.findUnique({ where: { id } }); // to'g'ridan-to'g'ri bazadan!
const html = marked(maqola.matn); // serverda ishlaydi
return (
<article>
<h1>{maqola.sarlavha}</h1>
<div dangerouslySetInnerHTML={{ __html: html }} />
<YoqtirishTugmasi maqolaId={id} boshlangich={maqola.yoqtirishlar} />
</article>
);
}
// app/maqola/[id]/YoqtirishTugmasi.jsx — CLIENT komponent
'use client';
import { useState } from 'react';
export default function YoqtirishTugmasi({ maqolaId, boshlangich }) {
const [son, setSon] = useState(boshlangich);
return <button onClick={() => setSon(son + 1)}>❤ {son}</button>;
}
Natija:
- Brauzer tayyor HTML oladi — maqola darhol ko'rinadi, Google ham ko'radi
markedva baza kodi brauzerga umuman yuborilmaydi — 0 KB- Faqat
YoqtirishTugmasining JavaScript i yuklanadi — interaktiv qism - API endpoint kerak emas — komponent ma'lumotni o'zi oladi
[!INFO] Server Components — React ning xususiyati, lekin ularni ishlatish uchun framework kerak: server, bundler sozlamalari va routing bilan. Hozir eng mashhuri — Next.js App Router; React Router (framework rejimi) va boshqalar ham qo'llab-quvvatlay boshlagan. Oddiy Vite + React SPA da Server Components yo'q.
Farqlar
| Server Component | Client Component | |
|---|---|---|
| E'lon qilish | Standart holat (Next.js App Router da) | Fayl boshida 'use client' |
| Qayerda bajariladi | Faqat serverda (build yoki so'rov vaqtida) | Serverda (birinchi HTML uchun) va brauzerda |
async komponent |
✅ await to'g'ridan-to'g'ri |
❌ |
| Ma'lumotlar bazasi, fayl tizimi, maxfiy kalitlar | ✅ | ❌ |
useState, useEffect, useReducer |
❌ | ✅ |
Hodisalar: onClick, onChange |
❌ | ✅ |
Brauzer API: window, localStorage |
❌ | ✅ |
Context ni o'qish (useContext) |
❌ | ✅ |
| JavaScript brauzerga yuboriladimi | ❌ Yo'q | ✅ Ha |
Oddiy qoida: interaktivlik kerak bo'lsa (state, hodisalar, effektlar, brauzer API) — Client. Qolgan hammasi — Server.
'use client' — chegara
'use client';
Bu direktiva bitta komponentni emas, chegarani belgilaydi: shu fayl va u import qiladigan barcha modullar client bundle ga kiradi.
page.jsx (server)
├── Sarlavha.jsx (server)
├── MaqolaMatni.jsx (server)
└── Izohlar.jsx 'use client' ← chegara
├── IzohFormasi.jsx (avtomatik client — import qilingan)
└── IzohQatori.jsx (avtomatik client)
Shuning uchun 'use client' ni daraxtning iloji boricha pastiga — faqat interaktiv "barglarga" qo'ying:
// ❌ butun sahifa client — barcha afzalliklar yo'qoladi
'use client';
export default function Sahifa() { ... }
// ✅ faqat interaktiv qism
export default async function Sahifa() { // server
const malumot = await olish();
return (
<>
<KattaStatikKontent malumot={malumot} /> {/* server */}
<QidiruvFormasi /> {/* 'use client' */}
</>
);
}
Kompozitsiya qoidalari
Server → Client: props orqali
// server
<YoqtirishTugmasi maqolaId={id} boshlangich={42} />
Props serializatsiya qilinadigan bo'lishi kerak — chunki ular tarmoq orqali yuboriladi: string, son, boolean, massiv, oddiy obyekt, Date, Promise. Funksiyalar — yo'q (Server Actions bundan mustasno):
// ❌ server komponentdan client ga funksiya
<Tugma onClick={() => console.log('bosildi')} />
Client ichida Server — faqat children orqali
Client komponent server komponentni import qila olmaydi (import qilingan hamma narsa client bo'lib qoladi). Lekin uni children sifatida qabul qila oladi:
// Modal.jsx
'use client';
export default function Modal({ children }) {
const [ochiq, setOchiq] = useState(false);
return ochiq ? <div className="modal">{children}</div> : <button onClick={() => setOchiq(true)}>Ochish</button>;
}
// page.jsx — server
<Modal>
<MahsulotTafsiloti id={id} /> {/* server komponent — serverda render bo'ladi */}
</Modal>
Bu 30-darsdagi composition naqshining server versiyasi.
Provider lar
Context faqat client da ishlaydi. Provider larni alohida client faylga chiqaring:
// app/providers.jsx
'use client';
export function Providers({ children }) {
const [queryClient] = useState(() => new QueryClient());
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
}
// app/layout.jsx — server
import { Providers } from './providers';
export default function RootLayout({ children }) {
return (
<html lang="uz">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
children (sahifalar) — baribir server komponentlar bo'lib qoladi.
Server Actions — ma'lumotni o'zgartirish
Server dan client ga funksiya berib bo'lmaydi — Server Action bundan mustasno:
// app/actions.js
'use server';
import { db } from '@/lib/db';
import { revalidatePath } from 'next/cache';
export async function izohQosh(formData) {
const matn = formData.get('matn');
if (!matn || matn.length < 2) return { xato: 'Izoh juda qisqa' }; // serverda tekshirish — majburiy
await db.izoh.create({ data: { matn } });
revalidatePath('/maqola');
}
// server yoki client komponentda
import { izohQosh } from './actions';
<form action={izohQosh}>
<textarea name="matn" required />
<button type="submit">Yuborish</button>
</form>
'use server' — funksiya serverda qoladi, client esa uni maxsus so'rov orqali chaqiradi. API endpoint yozish shart emas. Forma JavaScript yuklanmasdan oldin ham ishlaydi.
[!WARNING] Server Action — aslida ochiq API endpoint: har kim uni to'g'ridan-to'g'ri chaqira oladi. Har bir action ichida foydalanuvchi avtorizatsiyasini va kiruvchi ma'lumotni (masalan, Zod bilan — 65-dars) albatta tekshiring. Shuningdek, server-only kod (baza, maxfiy kalitlar) client ga tasodifan import qilinmasligi uchun
import 'server-only'dan foydalaning.
TanStack Query hali kerakmi?
| Vazifa | Server Components bilan |
|---|---|
| Sahifa uchun dastlabki ma'lumot | Server komponentda await — Query shart emas |
| Ma'lumotni o'zgartirish | Server Actions |
| Real vaqt yangilanish, polling, cheksiz lenta, optimistik UI, murakkab client kesh | TanStack Query hali ham foydali |
Server Components bilan client tomonidagi ma'lumot yuklash keskin kamayadi — lekin to'liq yo'qolmaydi.
Nima uchun shunday?
Nima uchun React jamoasi komponentlarni serverga qaytarishga qaror qildi — axir SPA lar aynan serverdan qochish uchun paydo bo'lgan edi-ku?
Chunki SPA lar bir muammoni hal qilib, boshqasini yaratdi. Ular ajoyib interaktivlik berdi, lekin buning narxi — har bir foydalanuvchining telefonida butun ilovani yuklash va bajarish, hatto sahifaning 90% i oddiy statik matn bo'lsa ham. Server Components "yo server, yo client" tanlovini komponent darajasida qiladi: har bir komponent o'zi uchun eng mos joyda ishlaydi. Statik kontent — serverda, bir marta, ma'lumotlar bazasi yonida; interaktiv qism — brauzerda. Bu ikkala dunyoning afzalliklarini birlashtiradi: PHP davridagi tez birinchi yuklash va SEO, SPA davridagi boy interaktivlik — va hammasi bitta komponent modelida.
Xulosa
Eslab qoling:
- Server Components — serverda bajariladi; brauzerga faqat natija, ularning JavaScript i yuborilmaydi
- Framework kerak — asosan Next.js App Router; oddiy Vite SPA da yo'q
- Server:
async, baza, maxfiy kalitlar; hook lar va hodisalar yo'q - Client:
'use client'— state, effektlar, hodisalar, brauzer API 'use client'— chegara; import qilinganlar ham client bo'ladi — uni daraxtning pastiga qo'ying- Server → Client props — serializatsiya qilinadigan; funksiya yo'q
- Client ichida server — faqat
childrenorqali; Provider lar — alohida client faylda - Server Actions (
'use server') — formalar va o'zgartirishlar; avtorizatsiya va validatsiya — majburiy
Keyingi dars
84-dars: Strict Mode — nima uchun kerak, double render sababi