Server Components — nima, Client Components dan farqi

~20 daq · React · Ilg'or mavzular

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
  • marked va baza kodi brauzerga umuman yuborilmaydi — 0 KB
  • Faqat YoqtirishTugmasi ning 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 children orqali; 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