EMZETT.
Giriş yap

Next.js App Router

Kısaca: Next.js’in yönlendirme ve işleme sistemi (13. sürümden beri); sayfalar varsayılan olarak sunucuda işlenir (“Sunucu Bileşenleri”) ve yalnızca açıkça işaretlenmiş kısımlar tarayıcıda çalışır (“İstemci Bileşenleri”, "use client").

Biraz daha ayrıntılı: ssr:false ile next/dynamic (bir bileşeni sunucu işlemesinden tamamen dışlamak) yalnızca bir İstemci Bileşeni içinde çalışır — bir Sunucu Bileşeninde (örneğin "use client" olmayan layout.tsx) bir uyarı değil, kesin bir derleme hatasıdır. npx tsc --noEmit yalnızca TypeScript türlerini denetler ve bu tür Next.js’e özgü kuralları yakalamaz — bunun için gerçek bir next build gerekir.

Bizim bağlamımız: Tam olarak bu türden bir ssr:false hatası bir keresinde derlemeyi bozdu — o zamandan beri her daha büyük toplu işten önce yalnızca TypeScript denetimi değil, gerçek bir npm run build çalıştırılır.

Ayrıntılı

Özel dosya adlarıyla dosya tabanlı yönlendirme

App Router, rotaları app/ altındaki klasör yapısıyla düzenler — her klasör bir URL bölümüne karşılık gelir ve içindeki bir page.tsx dosyası klasörü gerçek, erişilebilir bir sayfaya dönüştürür (page.tsx olmayan klasörler salt yapısaldır, örneğin ortak layout.tsx dosyaları için). Bu, her dosyanın otomatik olarak bir rota olduğu ve düzenlerin her sayfaya elle içe aktarılması gerektiği eski Pages Router’dan (pages/ dizini) temel bir farktır. page.tsx’in yanı sıra sabit anlamı olan bir dizi başka ayrılmış dosya adı vardır: layout.tsx altındaki tüm sayfaları sarar ve aynı düzen içindeki gezinmede kalıcıdır (yeniden bağlama yok), loading.tsx bir Sunucu Bileşeni yüklenirken otomatik olarak Suspense yedeği olarak gösterilir, error.tsx alt ağacındaki çalışma zamanı hatalarını yakalar (kendisi bir İstemci Bileşeni olmalıdır) ve not-found.tsx, notFound() çağrıldığında işlenir. Köşeli parantezli klasörler ([slug]) dinamik rota bölümleri oluşturur; üç noktalı köşeli parantezler ([...slug]) herhangi sayıda yol bölümünü aynı anda yakalar (“catch-all” rotalar).

Varsayılan olarak Sunucu Bileşenleri

Sunucu Bileşenleri varsayılandır: yalnızca sunucuda çalışır, veri tabanlarına/sırlara doğrudan erişir, ancak tarayıcıya KENDİLERİ JavaScript kodu göndermez — sonuç zaten hazır HTML’dir. İstemci Bileşenleri (dosyanın başında "use client") ise ek olarak JavaScript olarak tarayıcıya gönderilir ve etkileşimli olmaları için orada “hidrasyona” uğrar (onClick, useState, useEffect yalnızca orada çalışır). Pratik kural: mümkün olduğunca çoğunu Sunucu Bileşeni bırak ve "use client"’ı yalnızca tarayıcıda gerçek etkileşim gereken yerde ekle — her İstemci Bileşeni tarayıcıya gönderilen JavaScript paketini büyütür. Burada önemli: "use client" yönergesi yalnızca tek bir bileşeni değil, tüm modül sınırını işaretler — bir İstemci Bileşeni tarafından içe aktarılan her bileşen, kendisi useState kullanmasa bile istemci paketinin parçası olur.

// app/posts/[slug]/page.tsx — Sunucu Bileşeni (varsayılan, "use client" yok)
export default async function PostPage({ params }: { params: { slug: string } }) {
  const post = await db.query.posts.findFirst({ where: eq(posts.slug, params.slug) });
  return <article>{post?.title}</article>;
}

Sık kullanılan bir kalıp, küçük, etkileşimli bir İstemci Bileşenini bir Sunucu Bileşeninde children prop’u olarak gömerek Sunucu ve İstemci Bileşenlerini birleştirmektir — Sunucu Bileşeni bir İstemci Bileşeni “içerse” de yalnızca sunucuda kalır:

// app/layout.tsx — Sunucu Bileşeni, çocuk olarak bir İstemci Bileşeni işler
import { ThemeToggle } from "./theme-toggle"; // İstemci Bileşeni
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <ThemeToggle />
        {children}
      </body>
    </html>
  );
}

Veri yükleme ve önbellekleme

Sunucu Bileşenleri veri yüklemek için doğrudan async/await kullanabilir — bekleme, tarayıcıya HTML gitmeden önce sunucuda gerçekleştiğinden useEffect’e ve istemcide ayrı bir yükleme durumuna gerek yoktur. Next.js yerel fetch API’sini kendi önbellekleme davranışıyla genişletir: sonuçlar varsayılan olarak önbelleğe alınır ve cache: "no-store" ya da bir revalidate seçeneği açıkça ayarlanmadıkça derlemeler boyunca yeniden kullanılır. Bu, sunucu işlemesiz klasik React’ten gelen ve örtük bir “her istekte yeniden yükle” bekleyen yeni başlayanlar için sık bir hata kaynağıdır.

Tipik tuzaklar

next/dynamic ile bir ssr:false hatası (yukarıya bak), tsc’nin algılamadığı birkaç Next.js’e özgü kuraldan yalnızca biridir — yalnızca sunucuya ve yalnızca istemciye ait API’leri karıştırmak (örneğin bir Sunucu Bileşeninde window) da ancak next build sırasında ya da çalışma zamanında fark edilir. Bir diğer klasik hata: bir Sunucu Bileşeninden bir İstemci Bileşenine geçirilen prop’lar serileştirilebilir olmalıdır (işlev yok, sınıf örneği yok), çünkü sunucu/istemci sınırı boyunca fiilen “taşınmaları” gerekir.

Ayrıca bak: next-intl, Cache tag’leri ve revalidateTag