- Varsayılan: sunucu bileşeni, gerektiğinde istemci
- Karar ölçütleri: hangi bileşen nerede?
- use client sınırı nasıl çalışır?
- Sunucudan istemciye veri aktarmak: props ve children
- Context sağlayıcıları ve üçüncü taraf bileşenler
- Sunucu kodunun istemciye sızmasını önlemek
- Sık hatalar ve kontrol listesi
- Bu beceriyi Mindset programlarında nerede çalışırsınız
- Sık sorulan sorular
Sunucu mu istemci mi? Next.js bileşenlerini doğru yere koymak
Next.js'te hangi bileşenin sunucuda, hangisinin istemcide çalışacağını belirleme: use client sınırı, props aktarımı, context ve üçüncü taraf bileşenler.
Varsayılan: sunucu bileşeni, gerektiğinde istemci
App Router'da layout ve sayfalar varsayılan olarak sunucu bileşenidir. Bu bileşenler sunucuda çalışır; veritabanına ya da API'ye veriye yakın yerden erişir, gizli anahtarları kullanır ve tarayıcıya gönderilen JavaScript miktarını azaltır. İstemci bileşeni ise tarayıcıda etkileşim gereken yerlerde devreye girer: tıklama, yazma, durum tutma, tarayıcı API'leri.
Doğru ayrım için tek bir soruyu sorun: bu bileşen etkileşim ya da tarayıcı özelliği gerektiriyor mu? Gerektirmiyorsa sunucuda kalsın. Gerektiriyorsa yalnızca o küçük parçayı istemci bileşeni yapın; çevresindeki sayfanın geri kalanı sunucuda kalabilir.
Bu yaklaşım ürün ekiplerinde doğrudan sonuç üretir: istemciye gönderilen kod azalır, ilk içerik daha hızlı gelir ve veri çekme mantığı arayüz kodundan ayrılmadan sunucuda tutulur. Dokümantasyon bu kazancı ilk içerik boyama süresinin iyileşmesi ve içeriğin kademeli akıtılması olarak tarif eder.
Karar ölçütleri: hangi bileşen nerede?
İstemci bileşeni gerektiren durumlar: • Durum (state) ve olay yöneticileri: onClick, onChange gibi. • Yaşam döngüsü mantığı: useEffect gibi. • Tarayıcıya özgü API'ler: localStorage, window, navigator.geolocation gibi. • Özel kancalar (custom hooks).
Sunucu bileşeni gerektiren ya da tercih edilen durumlar: • Veritabanı veya API'den veriye kaynağa yakın yerden erişmek. • API anahtarı, belirteç gibi gizli bilgileri istemciye göstermeden kullanmak. • Tarayıcıya gönderilen JavaScript miktarını azaltmak. • İçeriği kademeli olarak istemciye akıtmak.
Örnek: bir ürün sayfasında başlık, açıklama ve fiyat sunucu bileşeninde çizilir; 'sepete ekle' düğmesi ve adet seçici ise istemci bileşenidir. Sayfa ürünü sunucuda çeker, istemci bileşenine yalnızca gereken değerleri özellik olarak geçirir:
import SepeteEkle from '@/app/ui/sepete-ekle' import { getProduct } from '@/lib/data'
export default async function Page({ params }: { params: Promise<{ id: string }> }) { const { id } = await params const product = await getProduct(id) return ( <div> <main> <p>{product.name}</p> <SepeteEkle productId={product.id} /> </main> </div> ) }
Karşılaştırma için kural: veri okuyan, etkileşimsiz ve gizli bilgi kullanan bileşen sunucuda; durum tutan, tıklanan ve tarayıcıya bağlı bileşen istemcide olsun.
use client sınırı nasıl çalışır?
Bir bileşeni istemci bileşeni yapmak için dosyanın en üstüne, import satırlarından önce use client yönergesini yazarsınız:
'use client' import { useState } from 'react'
export default function BegeniDugmesi() { const [begendi, setBegendi] = useState(false) return <button onClick={() => setBegendi(!begendi)}>{begendi ? 'Beğenildi' : 'Beğen'}</button> }
Bu yönerge, sunucu ve istemci modül grafikleri arasında bir sınır çizer. Bir dosya use client ile işaretlendiğinde, o dosyanın içe aktardığı her şey ve doğrudan çizdiği bileşenler istemci paketine girer. Bu yüzden yönergeyi her istemci bileşenine ayrı ayrı yazmanız gerekmez; sınırın başladığı dosyaya yazmanız yeterlidir.
Burada kritik bir ayrıntı vardır: sınır, yalnızca içe aktarma zincirini ve doğrudan çizilen bileşenleri kapsar. İstemci bileşenine children ya da başka bir özellik olarak geçirilen sunucu bileşenleri istemci modül grafiğine girmez; sunucuda çizilip sonuç olarak aktarılırlar.
Paket boyutunu küçük tutmanın yolu da buradan çıkar: yönergeyi büyük sayfa parçalarına değil, etkileşimli en küçük bileşenlere koyun. Örneğin bir layout'ta logo ve bağlantılar sunucu bileşeni kalır, yalnızca arama kutusu istemci bileşeni olur.
Sunucudan istemciye veri aktarmak: props ve children
Sunucu bileşeninden istemci bileşenine veri geçirmenin en yaygın yolu özelliklerdir (props). Aktardığınız değerler React tarafından serileştirilebilir olmalıdır; yani işlevler, sınıf örnekleri ve benzeri serileştirilemeyen nesneler doğrudan geçirilemez.
Bir başka yöntem, sunucu bileşenlerini istemci bileşenine children olarak vermektir. Bu sayede sunucuda veri çeken bir bileşeni, istemci durumuyla açılıp kapanan bir kapsayıcının içine yerleştirebilirsiniz:
// app/ui/modal.tsx 'use client' export default function Modal({ children }: { children: React.ReactNode }) { return <div>{children}</div> }
// app/page.tsx (sunucu bileşeni) import Modal from './ui/modal' import Sepet from './ui/sepet'
export default function Page() { return ( <Modal> <Sepet /> </Modal> ) }
Sepet bileşeni sunucuda önceden çizilir; sonuç, istemci bileşeninin ayırdığı boşluğa yerleşir. Sunucuda çizilen sonuç, React Server Component Payload adı verilen kompakt bir veri biçiminde taşınır; bu veri sunucu bileşenlerinin çizilmiş çıktısını, istemci bileşenleri için yer tutucuları ve aktarılan özellikleri içerir.
Bir sunucu bileşenini bir istemci bileşeninin içine doğrudan içe aktarmak (import) bu kalıbın yanlış uygulanmasıdır; sunucu bileşeni o durumda istemci paketine çekilir. Kalıp, her zaman 'üst sunucu bileşeninde birleştir, çocuk olarak geçir' biçiminde olmalıdır.
Context sağlayıcıları ve üçüncü taraf bileşenler
React context, sunucu bileşenlerinde desteklenmez. Tema gibi küresel durum için, children alan bir istemci bileşeni (sağlayıcı) yazar, onu sunucu bileşeni olan layout'ta kullanırsınız:
// app/tema-saglayici.tsx 'use client' import { createContext } from 'react' export const TemaBaglami = createContext({}) export default function TemaSaglayici({ children }: { children: React.ReactNode }) { return <TemaBaglami.Provider value="koyu">{children}</TemaBaglami.Provider> }
Sağlayıcıyı ağaçta olabildiğince derine koyun. Tüm html belgesini değil, yalnızca children'ı sarması, Next.js'in sunucu bileşenlerinizin statik kısımlarını optimize etmesini kolaylaştırır.
Üçüncü taraf paketler tarafında sık karşılaşılan sorun şudur: bir bileşen useState gibi istemci özellikleri kullanıyor ama paketi use client yönergesini taşımıyor. Böyle bir bileşeni doğrudan sunucu bileşeninde kullanırsanız hata alırsınız. Çözüm, onu kendi istemci bileşeninizle sarmaktır:
// app/carousel.tsx 'use client' import { Carousel } from 'acme-carousel' export default Carousel
Bundan sonra bu sarmalayıcıyı sunucu bileşenlerinde serbestçe kullanabilirsiniz. Kendi bileşen kitaplığınızı yayımlıyorsanız, istemci özelliği kullanan giriş noktalarına use client yönergesini kendiniz ekleyin; kullanıcılar sarmalayıcı yazmak zorunda kalmasın.
Sunucu kodunun istemciye sızmasını önlemek
JavaScript modülleri hem sunucu hem istemci bileşenleri arasında paylaşılabilir. Bu da sunucuya özgü kodu yanlışlıkla istemciye içe aktarmak anlamına gelebilir. Next.js'te yalnızca NEXT_PUBLIC_ önekli ortam değişkenleri istemci paketine girer; önek taşımayan değişkenler boş metinle değiştirilir. Yani gizli anahtar sızmaz ama işlev beklenmedik şekilde çalışmaz ve hata ayıklaması zorlaşır.
Bu tür hataları yapım aşamasında yakalamak için server-only paketini kullanın. Sunucuya özgü kod içeren dosyanın en üstüne bu paketi ekleyin; dosya bir istemci bileşeninden içe aktarılırsa derleme hatası alırsınız:
import 'server-only'
export async function veriGetir() { const yanit = await fetch('https://dis-servis.com/veri', { headers: { authorization: process.env.API_ANAHTARI }, }) return yanit.json() }
Tarayıcıya özgü kod için aynı mantıkla client-only paketi vardır. Bu paketleri kurmak isteğe bağlıdır; Next.js bunları dahili olarak ele alır, ancak lint kuralları gereksiz bağımlılık uyarısı veriyorsa kurabilirsiniz.
Sık hatalar ve kontrol listesi
- Her şeye use client yazmak: Paket büyür, sunucu bileşenlerinin avantajı kaybolur.
- Sunucu bileşenini istemci dosyasından içe aktarmak: Kalıbı children ile kurun.
- Serileştirilemeyen değeri özellik olarak geçirmek: Basit, serileştirilebilir değerler geçirin.
- Context'i sunucu bileşeninde kullanmaya çalışmak: Sağlayıcıyı istemci bileşeni olarak yazın.
- Üçüncü taraf bileşeni doğrudan sunucuda kullanmak: Kendi istemci sarmalayıcınızı yazın.
- Gizli bilgiyi istemci dosyasına koymak: Sunucu dosyalarına server-only ekleyin.
Bir bileşen yazarken sırayla şunu sorun: veri okuyor mu, etkileşim var mı, tarayıcı API'si kullanıyor mu? Etkileşim ya da tarayıcı API'si yoksa sunucuda bırakın. Varsa etkileşimli parçayı ayırın, yalnızca onu istemci bileşeni yapın ve çevresindeki bölümü sunucuda tutun. Bu ayrımı sayfa tasarımı aşamasında çizim üzerinde yapmak, sonradan refaktör yapmaktan çok daha ucuzdur.
Bu beceriyi Mindset programlarında nerede çalışırsınız
Next.js ile Full-Stack Web Uygulamaları programı, React biliyor ve bunu sunucu tarafı yetenekleriyle birleştirmek isteyen geliştiriciler için tasarlanmıştır. Sunucu ve istemci ayrımı, App Router Mimarisi modülünde ele alınan yapının doğal devamıdır; Veri Getirme ve Önbellekleme ile Performans ve Kullanıcı Deneyimi modülleri de bu ayrımın sonuçlarını işler.
Bir ürün ekibinde bu sınırın ortak bir kurala bağlanması, hem paket boyutu hem de güvenlik açısından incelemeleri kolaylaştırır.
İlgili Mindset programı
Next.js ile Full-Stack Web Uygulamaları
Sık sorulan sorular
Next.js'te bir bileşenin sunucu mu istemci mi olduğunu nasıl anlarım?
Dosyanın en üstünde use client yönergesi varsa istemci bileşenidir. Yönerge yoksa App Router'da bileşen varsayılan olarak sunucu bileşenidir. Ancak bir istemci bileşeninin içe aktardığı ya da doğrudan çizdiği bileşenler de istemci paketine girer, dolayısıyla etkili tür modül grafiğine de bağlıdır.
Sunucu bileşeni içinde useState kullanabilir miyim?
Hayır. State, useEffect ve olay yöneticileri gibi özellikler yalnızca istemci bileşenlerinde çalışır. Bu tür bir ihtiyaç duyduğunuzda etkileşimli parçayı ayrı bir dosyaya alıp başına use client yazarsınız ve sunucu bileşeninden özellik geçirerek kullanırsınız.
Context kullanabilmem için tüm uygulamayı istemci bileşeni yapmam gerekir mi?
Hayır. Children alan küçük bir istemci bileşeni (sağlayıcı) yazıp sunucu bileşeni olan layout içinde sarmalamanız yeterlidir. Böylece sağlayıcı yalnızca children'ı sarar ve uygulamanın geri kalanı sunucu bileşeni olarak kalabilir; sağlayıcıyı ağaçta olabildiğince derine koymak önerilir.
Sunucu bileşenini istemci bileşeninin çocuğu yapabilir miyim?
Evet. Üst bir sunucu bileşeninde istemci bileşenini sarıp aralarına sunucu bileşenini children olarak yerleştirirsiniz. Sunucu bileşeni sunucuda çizilir ve sonuç istemci bileşenine aktarılır. Sunucu bileşenini istemci dosyasında doğrudan içe aktarmak ise onu istemci paketine çeker.
server-only paketi zorunlu mu?
Hayır, kurulumu isteğe bağlıdır; Next.js server-only ve client-only içe aktarmalarını dahili olarak ele alır. Yine de sunucuya özgü dosyaların istemciye yanlışlıkla içe aktarılmasını yapım aşamasında hata olarak yakalamak için kullanmak iyi bir uygulamadır.