# Üretimde React Server Components: desenler ve tuzaklar > Üretimde React Server Components: savaşta sınanmış desenler, sık karşılaşılan anti-desenler ve sağlam Next.js 15 uygulamaları için hata ayıklama stratejileri. - Published: 2026-03-29 - Updated: 2026-05-04 - Author: Anthony Fillion-Maillet - Tags: react server components, next.js 15, rsc patterns, production, react 19 - Reading time: 9 min --- React Server Components (RSC), Next.js 15'te sunucu tarafı render'ın işleyişini temelden değiştirir; ancak üretim ortamındaki kullanım, resmi dokümantasyonun her zaman ele almadığı tuzakları ortaya çıkarır. Bu makale, çalışan desenleri, kırılan desenleri ve sorunların üretime ulaşmadan önce nasıl teşhis edileceğini ele alır. > **Server Components ve Client Components** > > Bir Server Component yalnızca sunucuda çalışır ve tarayıcıya sıfır JavaScript gönderir. Bir Client Component (`"use client"` ile işaretlenmiş) her iki tarafta da çalışır. Kural: Client Components'i mümkün olduğunca küçük ve ağacın mümkün olduğunca alt seviyesinde tutmak. ## Sunucu-istemci sınırı: boundary desenini anlamak En yaygın RSC tuzağı, Server ve Client Components arasındaki sınırla ilgilidir. Bir bileşen `"use client"` direktifini taşıdığında, **içe aktarılan tüm çocukları da Client Component haline gelir**, direktif olmasa bile. ```tsx // ProductPage.tsx (Server Component) import { ProductDetails } from './ProductDetails' import { AddToCartButton } from './AddToCartButton' export default async function ProductPage({ params }: { params: Promise<{ id: string }> }) { const { id } = await params const product = await getProduct(id) return (
{/* Server Component: doğrudan DB erişimi */} {/* Client Component: izole etkileşim */}
) } ``` ```tsx // AddToCartButton.tsx (Client Component) 'use client' import { useState } from 'react' export function AddToCartButton({ productId, price }: { productId: string; price: number }) { const [adding, setAdding] = useState(false) async function handleAdd() { setAdding(true) await fetch('/api/cart', { method: 'POST', body: JSON.stringify({ productId, quantity: 1 }), }) setAdding(false) } return ( ) } ``` Anahtar desen: verileri Server Component'tan Client Component'a **serileştirilebilir prop'lar** olarak geçirmek. Fonksiyonlar, sınıflar ve Date nesneleri bu sınırı geçemez. ## Anti-desen: gereksiz Client Component sarmalayıcısı Sık yapılan bir hata, Server Component çocuklarını saran bir Client Component oluşturmak ve böylece tüm alt ağacı istemci tarafına zorlamaktır. ```tsx // PageWrapper.tsx — ANTİ-DESEN 'use client' import { useState } from 'react' // Tüm çocuk içerik istemci tarafına geçer export function PageWrapper({ children }: { children: React.ReactNode }) { const [theme, setTheme] = useState('light') return (
{children}
) } ``` > **slot olarak children** > > Çözüm: Server Components'i `children` olarak geçirmek (slot deseni). Prop olarak geçirilen çocuklar, ebeveyn bir Client Component olsa bile Server Components olarak kalır. Yukarıdaki kod, `children` bir Server Component ebeveynden geldiği sürece doğru şekilde çalışır. ```tsx // layout.tsx (Server Component) import { PageWrapper } from './PageWrapper' import { HeavyServerContent } from './HeavyServerContent' export default function Layout() { return ( {/* İstemci sarmalayıcısına rağmen Server Component olarak kalır */} ) } ``` Bu kompozisyon deseni, ağır içerik için sunucu render'ının faydalarını korurken sarmalayıcı seviyesinde etkileşimi mümkün kılar. ## Asenkron veri işleme: bileşende fetch deseni React 19 ve Next.js 15, Server Components içinde doğrudan `async/await` desteği sunar. Bu desen, eski `getServerSideProps` yaklaşımına kıyasla veri çekmeyi basitleştirir. ```tsx // UserProfile.tsx (Server Component) import { cache } from 'react' // Aynı render içindeki özdeş çağrıları tekilleştirir const getUser = cache(async (userId: string) => { const res = await fetch(`https://api.example.com/users/${userId}`, { next: { revalidate: 3600 }, // 1 saat cache }) if (!res.ok) throw new Error('User not found') return res.json() }) export default async function UserProfile({ userId }: { userId: string }) { const user = await getUser(userId) return (

{user.name}

{user.email}

Üyelik tarihi: {new Date(user.createdAt).toLocaleDateString('tr-TR')}

) } ``` Üç kritik nokta: - React'in `cache()` fonksiyonu, tek bir sunucu render'ı sırasında özdeş çağrıları tekilleştirir - `next: { revalidate }`, Next.js tarafında cache süresini kontrol eder - Asenkron bir Server Component'taki hatalar en yakın `error.tsx`'i tetikler ## Serileştirme tuzağı: sınırı geçemeyenler Server ve Client Components arasında değişen verilerin JSON ile serileştirilebilir olması gerekir. Sessiz hatalara veya çökmelere yol açan durumlar şunlardır. ```tsx // TUZAK: serileştirilemez tipleri geçirmek // Fonksiyon — çalışmaz { /* server action */ }} /> // Bunun yerine içe aktarılmış bir Server Action kullanmak import { submitForm } from '@/lib/actions/form' // Date nesnesi — çalışmaz // ISO string — çalışır // Map, Set, RegExp — çalışmaz // Düz nesne veya dizi — çalışır ``` Server Actions (`"use server"` ile işaretli fonksiyonlar) istisnadır: Next.js bunları HTTP endpoint'lerine dönüştürdüğü için bir Client Component'a prop olarak geçirilebilirler. ## Streaming ve Suspense: ilerlemeli yükleme desenleri Suspense ile SSR streaming, HTML'i tarayıcıya ilerlemeli olarak gönderir. Optimal desen, her asenkron bölümün etrafında granüler Suspense sınırları kullanır. ```tsx // DashboardPage.tsx (Server Component) import { Suspense } from 'react' import { RevenueChart } from './RevenueChart' import { RecentOrders } from './RecentOrders' import { UserStats } from './UserStats' export default function DashboardPage() { return (
}> }> }>
) } ``` Her bölüm bağımsız olarak yüklenir. `RevenueChart` 3 saniye, `UserStats` 200 ms sürerse, istatistikler grafiği beklemeden anında görünür. > **Suspense ve SEO** > > Bir Suspense sınırı içindeki içerik sunucuda render edilir ve ilk HTML'e dahil edilir. Crawler'lar tam içeriği görür. Streaming yalnızca tarayıcıya teslim hızını etkiler, SEO görünürlüğünü değil. ## Üretimde hata ayıklama: RSC sorunlarını izleme RSC hataları çoğu zaman karmaşıktır. Üç teşhis tekniği üretimde işe yarar. **1. Hidrasyon uyumsuzluklarını tespit etmek** ```tsx // debug-hydration.tsx 'use client' import { useEffect, useState } from 'react' export function HydrationDebug() { const [isClient, setIsClient] = useState(false) useEffect(() => { setIsClient(true) }, []) if (process.env.NODE_ENV !== 'development') return null return (
{isClient ? 'Client' : 'Server'}
) } ``` **2. RSC payload'ını loglamak** Next.js 15'te `next.config.ts` içinde RSC log'larını etkinleştirmek: ```typescript // next.config.ts const nextConfig = { logging: { fetches: { fullUrl: true, // Tam fetch URL'lerini gösterir }, }, } export default nextConfig ``` **3. Payload boyutunu kontrol etmek** Aşırı büyük bir RSC payload'ı (> 128 KB) performansı düşürür. DevTools'ta `text/x-component` content type'lı ağ isteklerini izlemek gerekir. ## İleri desen: Server Actions ile kompozisyon Server Actions ve Server Components birleşimi doğal bir CQRS deseni oluşturur: sunucuda okumalar (RSC), action'lar üzerinden yazmalar. ```tsx // TodoList.tsx (Server Component) import { getTodos } from '@/lib/services/todo' import { TodoForm } from './TodoForm' import { deleteTodo } from '@/lib/actions/todo' export default async function TodoList() { const todos = await getTodos() return (
    {todos.map(todo => (
  • {todo.title}
  • ))}
) } ``` ```tsx // actions/todo.ts 'use server' import { revalidatePath } from 'next/cache' import { TodoService } from '@/lib/services/todo' export async function deleteTodo(formData: FormData) { const id = formData.get('id') as string await TodoService.delete(id) revalidatePath('/todos') } ``` `revalidatePath` çağrısı, tam sayfa yenilemesi olmadan güncellenmiş verilerle yeni bir Server Component render'ını tetikler. Bu konularda daha derin mülakat hazırlığı için SharpSkill'deki [Next.js Server Actions](/technologies/react-next/interview-questions/nextjs-server-actions) modülü ile [Next.js Data Fetching](/technologies/react-next/interview-questions/nextjs-data-fetching) modülünü incelemek faydalıdır. [Resmi React dokümantasyonu](https://react.dev/reference/rsc/server-components) Server Components spesifikasyonunun tamamını ele alır. ## Sonuç - Client Components'i bileşen ağacının altında küçük ve izole tutmak - Bir istemci sarmalayıcısı içinde Server Components'i korumak için slot desenini (`children`) kullanmak - Sunucu-istemci sınırını geçen prop'ların serileştirilebilirliğini her zaman doğrulamak - Her bağımsız asenkron bölümün etrafına granüler Suspense sınırları yerleştirmek - Üretimde RSC payload boyutunu izlemek (hedef < 128 KB) - Doğal bir CQRS deseni için Server Components (okumalar) ve Server Actions (yazmalar) birleşimini kullanmak - Tek bir sunucu render'ı içindeki istekleri tekilleştirmek için React'in `cache()` fonksiyonunu kullanmak --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/tr/blog/react-next/react-server-components-patterns-pitfalls