- Next.js'in gelecekteki yönü heyecan verici görünüyor
- Server Actions ile ilgili bazı sorunlar vardı, ancak React 19'daki
useOptimistic, useFormStatus ile iyileşme potansiyeli görülüyor
- Remix'in
useFetcher yaklaşımı da iyi bir DX sunuyor
- Next.js'in PPR'ı (Partial Pre-rendering) ve yeni granular önbellek sistemi özellikle öne çıkıyor
- Genel olarak çok olumlu bir izlenim edindim
Büyük Resim
- Yeni önbellek sistemi
next.config.js içinde deneysel olarak etkinleştirilebiliyor
- Önbellek profilleri tanımlanarak farklı sona erme süreleri ve yeniden doğrulama aralıkları ayarlanabiliyor
// next.config.js
const config = {
experimental: {
// Yeni önbellekleme sistemini etkinleştir. Artık kod içinde `use cache` kullanılabilir
dynamicIO: true,
// İsteğe bağlı: önbellek profili ayarları
cacheLife: {
blog: {
stale: 3600, // istemci önbelleğini koru: 1 saat
revalidate: 900, // sunucuda yenile: 15 dakika
expire: 86400, // maksimum ömür: 1 gün
},
},
},
};
use cache temel kullanımı
- Dosya, bileşen ve fonksiyon seviyesinde
"use cache" bildirimiyle önbellekleme yapılabiliyor
- Kod örneklerinde
use cache eklenerek önbellek kolayca uygulanabiliyor
cacheTag, revalidateTag gibi araçlar kullanılarak istenen anda önbellek geçersiz kılınabiliyor
// 1. dosya düzeyinde önbellekleme
"use cache";
export default function Page() {
return <div>Cached Page</div>;
}
// 2. bileşen düzeyinde önbellekleme
export async function PriceDisplay() {
"use cache";
const price = await fetchPrice();
return <div>${price}</div>;
}
// 3. fonksiyon düzeyinde önbellekleme
export async function getData() {
"use cache";
return await db.query();
}
Etiket tabanlı önbellekleme
import { unstable_cacheTag as cacheTag, revalidateTag } from 'next/cache';
// Belirli bir veri grubunu önbelleğe al
export async function ProductList() {
'use cache';
cacheTag('products');
const products = await fetchProducts();
return <div>{products}</div>;
}
// Veri değiştiğinde önbelleği geçersiz kıl
export async function addProduct() {
'use server';
await db.products.add(...);
revalidateTag('products');
}
Özel Cache profilleri
unstable_cacheLife kullanılarak next.config.js içinde tanımlanan önbellek profilleri çağrılabiliyor
- Kod içinde bildirilen profil adı (ör.
"blog") kullanılarak önbellek politikası uygulanıyor
import { unstable_cacheLife as cacheLife } from "next/cache";
export async function BlogPosts() {
"use cache";
cacheLife("blog"); // Önceden tanımlanmış blog önbellek profili kullanılır
return await fetchPosts();
}
Önemli ama gözden kaçabilecek noktalar
Önbellek anahtarının otomatik oluşturulması
- Bileşenin
props ve arguments değerleri otomatik olarak önbellek anahtarına dahil edilir
- Serileştirilemeyen değerler (fonksiyonlar gibi) "değiştirilemez referans" biçiminde ele alınır
export async function UserCard({ id, onDelete }) {
"use cache";
// id önbellek anahtarına dahil edilir
// onDelete iletilir ama önbelleklemeyi etkilemez
const user = await fetchUser(id);
return <div onClick={onDelete}>{user.name}</div>;
}
Dinamik içerik ile önbelleğe alınmış içeriğin karıştırılması
- Önbelleğe alınmış içeriğin içine dinamik içerik çocuk olarak geçirilip birlikte kullanılabiliyor
cacheTag dizisi belirtilerek birden fazla etiket aynı anda uygulanıp geçersiz kılınabiliyor
export async function CachedWrapper({ children }) {
"use cache";
const header = await fetchHeader();
return (
<div>
<h1>{header}</h1>
{children} {/* Dinamik içerik olduğu gibi korunur */}
</div>
);
}
export async function ProductPage({ id }) {
"use cache";
cacheTag(["products", `product-${id}`, "featured"]);
// Bu etiketlerden herhangi biri kullanılarak geçersiz kılınabilir
}
Önbellekleme hiyerarşisi
- En üst seviyede
"use cache" bildirildiğinde ilgili alanın tamamı önbelleğe alınır
- Belirli bölümler (ör. Suspense kullanan dinamik alanlar) önbellek kapsamı dışında bırakılabilir
"use cache";
export default async function Page() {
return (
<div>
<CachedHeader />
<div>
<Suspense fallback={<Loading />}>
<DynamicFeed /> {/* Dinamik içerik */}
</Suspense>
</div>
</div>
);
}
Tip güvenliği
- Önbellek anahtarları ve önbellek profilleri gibi string'ler sabitler olarak yönetilerek magic string kullanımı azaltılabiliyor
- React Query'deki desenlere benzer şekilde etiket üreten bir yaklaşım kullanmak pratik oluyor
// Önbellek profil anahtarlarını sabit olarak yönet
export const CACHE_LIFE_KEYS = {
blog: "blog",
} as const;
const config = {
experimental: {
cacheLife: {
[CACHE_LIFE_KEYS.blog]: {
stale: 3600,
revalidate: 900,
expire: 86400,
},
},
},
};
Önbellek etiketlerini verimli yönetme yöntemi
- React Query tarzı etiket fabrikası deseni uygulama
export const CACHE_TAGS = {
blog: {
all: ["blog"] as const,
list: () => [...CACHE_TAGS.blog.all, "list"] as const,
post: (id: string) => [...CACHE_TAGS.blog.all, "post", id] as const,
comments: (postId: string) =>
[...CACHE_TAGS.blog.all, "post", postId, "comments"] as const,
},
} as const;
// Önbellek etiketlerini ayarla
function tagCache(tags: string[]) {
cacheTag(...tags);
}
// Kullanım örneği
export async function BlogList() {
"use cache";
tagCache(CACHE_TAGS.blog.list());
}
3 yorum
SEO önemli olduğu için SSR gereken durumlarda yalnızca Next.js veya Remix gibi framework'leri kullanmanın iyi olduğunu düşünüyorum.
Özellikle B2B iş ürünleri ya da back office gibi SEO'nun önemli olmadığı hizmetlerde Next.js'i benimsemenin dikkatle değerlendirilmesi gerektiğini düşünüyorum. Çünkü Next.js'in dayattığı arayüzler veya karmaşıklık, geliştirme verimliliğini düşürebilir.
Kişisel olarak, SEO'nun gereksiz olduğu durumlarda Vite + React'in geliştirme verimliliği ve esneklik gibi açılardan çok daha iyi olduğunu düşünüyorum.
Next.js, 13'ten sonra gerçekten epey kullanışlı hale gelmişti ama son dönemde gerçekten ama gerçekten çok hoşuma gidiyor. Full-stack web geliştirme teknoloji yığınının fiili standardı olacak gibi görünüyor.