React Server Components Nedir? RSC Rehberi

## React Server Components Nedir? React Server Components (RSC), React bileşenlerinin bir kısmının sunucuda, bir kısmının istemcide çalışmasına izin...

React Server Components Nedir? RSC Rehberi

React Server Components Nedir?

React Server Components (RSC), React bileşenlerinin bir kısmının sunucuda, bir kısmının istemcide çalışmasına izin veren bir mimaridir. Amaç, veri çekme ve ağır bağımlılıkları sunucuda tutarken, etkileşimli kısmı istemcide çalıştırmaktır. Sonuç olarak istemciye gönderilen JavaScript miktarı azalır ve veriye doğrudan sunucudan erişilebilir.

RSC bir kütüphane değil, bir çalışma modelidir. React'in kendisi bileşen türünü ayırt eder; ancak bu modeli uçtan uca kullanmak için bir framework gerekir. Bugün pratikte en yaygın kullanım Next.js App Router üzerinden olur. Bu rehber React 19 ve Next.js App Router varsayımıyla yazılmıştır; sürüm numarası vermediğim yerlerde davranış bu iki sürüm hattında geçerlidir.

Önkoşullar

  • React bileşenleri, props ve state konularında rahat olmak.
  • Sunucu ve istemci arasındaki ayrımı (istek/yanıt döngüsü) kavramış olmak.
  • Next.js App Router veya benzeri bir RSC destekli framework kurulumu.
  • Node.js ve paket yöneticisi kurulu bir geliştirme ortamı.

RSC'yi framework olmadan elle kurmak mümkündür ama üretimde beklenen faydayı vermez; bu yazı framework üzerinden ilerler.

Temel Ayrım: Sunucu ve İstemci Bileşenleri

App Router'da bir dosyadaki bileşen, dosyanın en üstünde "use client" yönergesi yoksa varsayılan olarak Server Component'tir. "use client" yazıldığında o modül ve içe aktardığı modüller Client Component olur.

  • Server Component: Sunucuda çalışır, istemciye JavaScript göndermez (kendi kodu için), veritabanına veya dosya sistemine doğrudan erişebilir, useState/useEffect gibi hook'ları kullanamaz, tarayıcı API'lerine erişemez.
  • Client Component: Tarayıcıda (ve ön-render için sunucuda) çalışır, state ve efekt kullanabilir, olay dinleyicileri ekleyebilir, ancak sunucu tarafı kaynaklara doğrudan erişemez.

Kritik nokta: Bir Server Component, bir Client Component'i içe aktarıp render edebilir. Tersi mümkün değildir; bir Client Component, Server Component'i doğrudan içe aktaramaz. Bir Client Component'in içine sunucu tarafı bir bileşen koymak istiyorsanız, onu children prop'u olarak dışarıdan geçirirsiniz.

Adım Adım: Basit Bir RSC Akışı

1. Sunucuda veri çeken bir bileşen yazın

app/posts/page.tsx:

// "use client" yok: bu bir Server Component
async function getPosts() {
  const res = await fetch("https://example.com/api/posts", {
    cache: "no-store",
  });
  if (!res.ok) throw new Error("Gönderiler alınamadı");
  return res.json();
}

export default async function PostsPage() {
  const posts = await getPosts();
  return (
    <ul>
      {posts.map((p: { id: string; title: string }) => (
        <li key={p.id}>{p.title}</li>
      ))}
    </ul>
  );
}

Beklenen davranış: Bileşen sunucuda await ile veriyi çeker, HTML üretilir ve istemciye gönderilir. Bu bileşenin kodu istemci paketine dahil olmaz. async bileşen yalnızca Server Component'lerde geçerlidir; Client Component'lerde kullanılamaz.

2. Etkileşim gereken kısmı Client Component yapın

app/posts/like-button.tsx:

"use client";

import { useState } from "react";

export default function LikeButton({ initialCount }: { initialCount: number }) {
  const [count, setCount] = useState(initialCount);
  return (
    <button onClick={() => setCount((c) => c + 1)}>
      Beğeni: {count}
    </button>
  );
}

Beklenen davranış: Buton istemcide çalışır, tıklamaya tepki verir. useState yalnızca burada kullanılabilir.

3. İkisini birleştirin

app/posts/page.tsx içinde:

import LikeButton from "./like-button";

export default async function PostsPage() {
  const posts = await getPosts();
  return (
    <ul>
      {posts.map((p: { id: string; title: string }) => (
        <li key={p.id}>
          {p.title} <LikeButton initialCount={p.likes} />
        </li>
      ))}
    </ul>
  );
}

Beklenen davranış: Sunucu bileşeni listeyi çeker, her öğe için Client Component'e başlangıç değeri props olarak geçer. Client Component sunucuda ön-render edilir, sonra istemcide etkileşim kazanır.

Sınırlar ve Props Kuralları

Sunucu-istemci sınırında props'lar serileştirilebilir olmalıdır. Fonksiyonlar, sınıf örnekleri veya DOM düğümleri geçirilemez. Bu, RSC'de en sık karşılaşılan kısıttır.

  • Geçirilebilir: string, number, boolean, null, dizi, düz nesne, Date, Map, Set, Promise (streaming senaryolarında), React element.
  • Geçirilemez: olay işleyicileri (onClick gibi), tanımsız fonksiyonlar, tarayıcıya özgü nesneler.

Bir Client Component'e onClick prop'u geçmek istiyorsanız, bu işleyici zaten Client Component içinde tanımlanmalıdır; sunucudan fonksiyon geçirilemez.

Yaygın Hatalar

  • "use client" yönergesini gereksiz yere en üste koymak. Bu, alt ağacın tamamını istemci paketine taşır ve RSC'nin faydasını ortadan kaldırır. Yönergeyi yalnızca etkileşim veya tarayıcı API'si gereken en alt seviyedeki bileşenlere koyun.
  • Server Component içinde hook kullanmaya çalışmak. useState, useEffect, useContext yalnızca Client Component'lerde çalışır.
  • Client Component içinde Server Component'i doğrudan import etmek. Derleme hatasına yol açar veya bileşeni istemciye taşır. Çözüm: bileşeni children olarak dışarıdan geçirin.
  • Sunucudan istemciye serileştirilemeyen değer geçirmek. Fonksiyon veya benzeri değerler runtime hatası verir.
  • Her şeyi async yapmak. async bileşenler yalnızca Server Component'lerde geçerlidir; Client Component'lerde kullanılamaz.

Güvenlik Etkileri

Server Component kodu istemciye gönderilmediği için, veritabanı sorguları, API anahtarları veya dosya sistemi erişimi istemciye sızmaz. Ancak bu, dikkat gerektirmeyen bir alan değildir:

  • Ortam değişkenleri: Sunucu tarafı gizli anahtarları yalnızca sunucuda kullanın. NEXT_PUBLIC_ gibi istemciye açık öneklerle tanımlanan değişkenler istemci paketine gömülür; gizli değerleri bu önekle tanımlamayın.
  • Yetkilendirme: Veri çekme işlemi sunucuda yapıldığı için yetki kontrolü de orada yapılmalıdır. Sadece istemcide gizlemek yeterli değildir; sunucu bileşeni, istek sahibinin o veriye erişme yetkisi olup olmadığını doğrulamalıdır.
  • Kullanıcı girdisi: Sunucuda işlenen girdiler yine doğrulanmalı ve temizlenmelidir. RSC, SQL enjeksiyonu veya XSS gibi riskleri kendiliğinden ortadan kaldırmaz.
  • "use client" sınırına dikkat: İstemciye geçirilen props'lar istemci tarafında görünür. Hassas veriyi bu sınırın ötesine taşımayın.

Ne Zaman RSC, Ne Zaman Client Component?

  • Veri çekme, veritabanı erişimi, ağır işlemler: Server Component.
  • Form doğrulama, etkileşim, tarayıcı API'leri, state: Client Component.
  • Liste/veri sunumu ve etkileşim karışıksa: veri ve düzeni Server Component'te tutun, etkileşimli parçaları küçük Client Component'lere ayırın.

Bu ayrımı korumak, RSC'nin sağladığı paket boyutu ve veri erişimi avantajlarını korur. Aksi halde "use client" yönergesi tüm ağacı istemciye taşır ve modelin amacı ortadan kalkar.

İLGİLİ İÇERİKLER

Bunları da Okumak İsteyebilirsiniz