On yıl boyunca "tek sayfa uygulama" demek, tarayıcıda çalışan tek bir büyük JavaScript paketi demekti. Veri API'den çekilir, HTML tarayıcıda kurulur, ilk ekran iskelet ekranlarla beklerdi. React Server Components (RSC) bu tabloyu tersine çeviriyor: bileşenlerin çoğu yeniden sunucuda render ediliyor — ama sayfa yenilenmeden, SPA akıcılığı korunarak.
Sorun: her şey tarayıcıya gidiyor
Klasik bir React uygulamasında ürün sayfası düşünün. Sayfanın dokuz yüzde dokuzu statik: başlık,
fiyat, açıklama, fotoğraf. Yalnızca "Sepete Ekle" düğmesi etkileşimli. Yine de React'in kendisi,
routing kütüphanesi, veri çekme mantığı — hepsi kullanıcının telefonuna iner. Kullanıcıya hiç
görüntülenmeyecek veri için useEffect içinde spinner'lı istekler atılır. RSC'nin vaadi
basittir: etkileşimli olmayan hiçbir kod tarayıcıya gönderilmesin.
// app/urun/[id]/page.tsx — SUNUCU BİLEŞENİ
// "use client" satırı YOK: bu dosya hiçbir zaman tarayıcıya inmez.
import { db } from '@/lib/db';
import AddToCart from './add-to-cart';
export default async function UrunSayfasi({
params,
}: {
params: Promise<{ id: string }>;
}) {
// Veri çekme artık sunucuda: fetch + useEffect + spinner yok.
// Doğrudan veritabanına çağrı yapıyoruz — API katmanı bile zorunlu değil.
const { id } = await params;
const urun = await db.product.findUnique({ where: { id } });
if (!urun) notFound();
return (
<main>
<h1>{urun.ad}</h1>
<p>{urun.fiyat} TL</p>
{/* Yalnızca bu etkileşimli parça client paketine girer: */}
<AddToCart productId={urun.id} />
</main>
);
}
"use client" bir çizgi, bir moda değil
Karşıtın sandığı gibi RSC, client component'lerin yasaklandığı bir rejim değil. "use client"
bir dosyanın başına konan bir sınır işaretidir: bu çizginin altındaki kod hidratlanır, state
tutar, event dinler. Üstünde kalan her şey sunucuda kalır. Kural da gayet pratiktir — sayfayı
ağaç gibi düşünün: gövde (veri, düzen, metin) sunucuda, yapraklar (buton, form, sekmeler)
istemcide. Tecrübeyle sabit olmuş bir oran var: tipik bir sayfanın yüzde 90'ı sunucu bileşeni
olabiliyor ve sonuç, iletilen JavaScript miktarında ciddi bir düşüş.
El sıkışmanın anatomisi
Sunucu bileşeninden client bileşenine veri, prop olarak geçilir — ama bu prop'ların
serileştirilebilir olması şartı var. Fonksiyon veya sınıf örneği geçemezsiniz; sayı, metin,
düz nesne geçersiniz. Sunucu, render çıktısını JSON benzeri bir akış olarak tarayıcıya yollar;
istemci yalnızca "use client" olarak işaretlenmiş parçaları indirir ve hidratlar. Bu akış
sayesinde async bir bileşen yazmak, await ile veri beklemek meşrudur — React bunu ilk kez
bir anti-desen olmaktan çıkardı.
Geçişin pratikteki görünümü şudur: sunucu bileşeni, client bileşenine düz veri ve serileştirilebilir değerler gönderir; client bileşeni ise sunucuya yalnızca eylem (action) üzerinden döner. Ağdaki bu iki yön, eski mimarideki REST/JSON dansının yerini bambaşka bir sözleşmeye bırakır:
// add-to-cart.tsx — "use client" ile başlar, hidratlanır ve etkileşimlidir
'use client';
export default function AddToCart({ productId }: { productId: string }) {
// Server Action: istemciden sunucudaki fonksiyona doğrudan çağrı
const ekle = async () => {
await sepeteEkle(productId); // sunucuda çalışır, istemci kodu değil
};
return <button onClick={ekle}>Sepete Ekle</button>;
}
Sonuç: RSC, "sunucuya dönmek" değil, sunucu ile istemci arasında işi doğru yerde paylaştırmak. Doğru yerde paylaşıldığında hem paketler küçülüyor hem de veri çekme kablosu karmaşası kayboluyor.
Okur Yorumları (0)