Next.js Questions
CSR, SSR, SSG, PPR, ISR
CSR (Client-Side Rendering):
- رندر سمت مرورگر بعد از دانلود جاوااسکریپت.
- مناسب داشبوردها و اپلیکیشنهای کاملاً تعاملی
"use client";
import { useEffect, useState } from "react";
export default function CSRPage() {
const [data, setData]
= useState(null);
useEffect(() => {
fetch("/api/hello")
.then(r => r.json())
.then(d => setData(d));
}, []
);
return (
<div>
<h1>CSR Page</h1>
<p>{data ? data.message : "Loading..."}</p>
</div>
);
}
SSR (Server-Side Rendering):
- خب HTML در هر درخواست روی سرور ساخته میشود
- مناسب صفحات شخصیسازیشده (پروفایل، پنل کاربری)
export default async function SSRPage() {
const res = await fetch("https://api.example.com/data", {
cache: "no-store", // کلید طلایی SSR
});
const data = await res.json();
return (
<div>
<h1>SSR Page</h1>
<p>{data.title}</p>
</div>
);
}
SSG (Static Site Generation):
- صفحه یک بار در build-time ساخته میشه و روی سرور کش میشه، و همیشه همون فایل html سرو میشه
- سریع، امن و عالی برای SEO
export const dynamic = "force-static";
export default async function SSGPage() {
const data = await fetch("https://api.example.com/data").then(r => r.json());
return (
<div>
<h1>SSG Page</h1>
<p>{data.title}</p>
</div>
);
}
ISR (Incremental Static Regeneration):
- همون SSG هستش که صفحه استاتیکه ولی هر X ثانیع یکبار دوباره بروزرسانی میشه
- بازسازی صفحه بدون rebuild کل پروژه
- ترکیب SSG و SSR
export const revalidate = 10; // هر 10 ثانیه صفحه re-generate میشود
export default async function ISRPage() {
const data = await fetch("https://api.example.com/data").then(r => r.json());
return (
<div>
<h1>ISR Page</h1>
<p>{data.title}</p>
<small>Regenerate every 10 sec</small>
</div>
);
}
PPR (Partial Prerendering) :
بخشی از صفحه سرور استاتیک میاد، بخشهایی که نیاز به دیتا دارن به شکل تعلیقی و استریم بعداً لود میشن.
این روش برای صفحات بزرگتر فوقالعادهست
- تركيب محتواى استاتيک و دايناميک دريک درخواست HTTP
- بهينهسازى عملكرد با استريم همزمان كاميوننتهاى دايناميک
import { Suspense } from "react";
// این بخش async بعداً stream میشود
async function DynamicSection() {
const res = await fetch("https://api.example.com/slow-data", {
cache: "no-store",
});
const data = await res.json();
return <p>Dynamic data: {data.title}</p>;
}
export default function PPRPage() {
return (
<div>
<h1>Partial Prerendering (PPR)</h1>
{/* این بخش استاتیک است */}
<p>This section is pre-rendered instantly.</p>
{/* این بخش بعدا stream میشود */}
<Suspense fallback={<p>Loading dynamic section...</p>}>
<DynamicSection />
</Suspense>
</div>
);
}
نکته: ISR بهترین انتخاب برای بلاگها، لندینگها و محتواهای نیمهداینامیک است.
Caching Layers
خب Next.js به طور پیشفرض fetch را cache میکند.
اما Next چند لایه کش داره
Request Memoization
در یک رندر اگر چند بار یک fetch انجام بدی Next فقط یکبار request میزند.
await fetch("/api/products");
await fetch("/api/products");
Data Cache
وقتی fetch میکنی Next پاسخ API را cache میکند.
fetch(url, { cache: "force-cache" });
// Or
fetch(url, { next: { revalidate: 60 } }); // هر 60 ثانیه revalidate
بهش میگن:
ISR (Incremental Static Regeneration)
Full Route Cache
اگر صفحه static باشد Next کل خروجی HTML را cache میکند.
Router Cache (Client)
در client navigation Next صفحات را در حافظه مرورگر cache میکند
بنابراین back navigation سریع میشود.
<Link />
Route Handler
جایگزین API Routes قدیمی در App Router است.
app / api / users / route.ts;
Server Actions در Next.js 14/15
اجازه میدهد تابع server را مستقیم از form صدا بزنیم بدون API.
یا Server Actions اجازه میدهند مستقیم یک function server را صدا بزنی.
"use server";
export async function createUser(formData: FormData) {
const name = formData.get("name");
await db.user.create({
data: { name },
});
}
استفاده در فرم:
<form action={createUser}>
<input name="name" />
<button type="submit">Save</button>
</form>
مزایا:
- حذف API layer
- امنیت بیشتر
- performance بهتر
Pages Router Vs App Router
| Page Router | App Router |
|---|---|
| Old | New |
| getServerSideProps | Fetch مستقیم |
| API Router | route handlers |
| layout محدود | nested layouts |
| React 18 features کمتر | streaming/suspense |
Hydration Error
اگر خروجی سرور با خروجی کلاینت متفاوت باشد، React خطای Hydration mismatch میدهد.
مثال مشکل
export default function Page() {
return <p>{Date.now()}</p>;
}
چرا مشکل دارد؟
چون:
- سرور یک timestamp میسازد
- کلاینت timestamp دیگری
پس HTML متفاوت میشود.
راه حل
استفاده از Client Component
"use client";
import { useEffect, useState } from "react";
export default function Page() {
const [time, setTime]
= useState(0);
useEffect(() => {
setTime(Date.now());
}, []
);
return <p>{time}</p>;
}
Turbopack
Turbopack نسل جدید bundler در Next.js است که توسط Vercel ساخته شده.
جایگزین:
- Webpack
ویژگیها
- نوشته شده با Rust
- سرعت build بسیار بالا
- incremental bundling
- dev server بسیار سریع
فعال سازی:
next dev --turbo
next/font
در Next.js میتوان فونت را self-hosted کرد.
بدون نیاز به Google CDN.
import { Inter } from "next/font/google";
const inter = Inter({ subsets: ["latin"]
});
export default function Layout({ children }) {
return <body className={inter.className}>{children}</body>;
}
مزایا:
- zero layout shift
- privacy بهتر
- performance بهتر
Link Vs a tag
در Next.js باید از next/link استفاده کرد.
چرا؟
چون:
- client-side navigation
- prefetch
- سریعتر
import Link from "next/link";
<Link href="/about">About</Link>;
خب Next.js لینکها را قبل از کلیک preload میکند.
غیرفعال کردن:
<Link href="/about" prefetch={false}>
چرا Next.js سریعتر از CRA است؟
- SSR / SSG
- code splitting خودکار
- image optimization
- streaming
- server components
- turbopack
اگر صفحهای داری که 90٪ static است ولی یک widget realtime دارد، چه میکنی؟
- صفحه را static میسازم
- و widget را client component میکنم
- یا dynamic import
const ChatWidget = dynamic(() => import("./ChatWidget"), {
ssr: false,
});