Next.js App Router: Patterns cho Production
Hướng dẫn thực chiến xây dựng web app nhanh với Next.js App Router — server components, streaming, parallel routes, caching strategies.
Next.js App Router là một thay đổi căn bản trong cách tổ chức và render React app. Đây là các pattern Ventra Rocket sử dụng trong production.
1. Server Components là mặc định
Server Components không gửi JavaScript xuống client — lý tưởng cho data fetching.
// app/dashboard/page.tsx — Server Component mặc định
async function DashboardPage() {
const metrics = await fetchMetrics(); // gọi DB trực tiếp
return <MetricsGrid data={metrics} />;
}
Quy tắc:
- Data fetching → Server Component
- Tương tác (onClick, useState) → Client Component (
"use client") - Browser APIs (localStorage) → Client Component
2. Streaming với Suspense
import { Suspense } from "react";
export default function Page() {
return (
<main>
<HeroSection />
<Suspense fallback={<SkeletonCard />}>
<SlowDataComponent />
</Suspense>
</main>
);
}
Dùng loading.tsx cho route-level loading UI — tự động là Suspense wrapper cho page.tsx.
3. Route Handler cho API
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
const page = Number(request.nextUrl.searchParams.get("page") ?? 1);
const users = await db.users.findMany({ skip: (page - 1) * 10, take: 10 });
return NextResponse.json({ users, page });
}
4. Chiến lược Cache
| Layer | Cơ chế | Thời gian | |-------|--------|-----------| | Request Memoization | React cache | Mỗi render | | Data Cache | fetch + next.revalidate | Persistent | | Full Route Cache | Static HTML | Build time | | Router Cache | Client-side | Per session |
// ISR: revalidate mỗi giờ
const data = await fetch("https://api.example.com/config", {
next: { revalidate: 3600 },
});
// Luôn fresh
const live = await fetch("https://api.example.com/prices", {
cache: "no-store",
});
5. Middleware cho Auth
export function middleware(request: NextRequest) {
const token = request.cookies.get("auth_token");
const isProtected = request.nextUrl.pathname.startsWith("/dashboard");
if (isProtected && !token) {
return NextResponse.redirect(new URL("/login", request.url));
}
return NextResponse.next();
}
export const config = { matcher: ["/dashboard/:path*"] };
Kết luận
App Router hoạt động tốt nhất khi: đẩy data fetching lên server, dùng Suspense cho async boundaries, và cân nhắc kỹ về Client Components. Ventra Rocket đã deploy nhiều Next.js 15 app với Time to First Byte dưới 1 giây.
Bài viết liên quan
10 TypeScript Pattern giúp code sạch hơn
Tổng hợp 10 TypeScript pattern thực tiễn — từ discriminated unions, template literal types đến satisfies operator — giúp code type-safe và dễ bảo trì.
Quản lý State trong React 2026: Zustand, TanStack Query và URL State
Chọn đúng công cụ quản lý state trong React — TanStack Query cho server state, Zustand cho global UI state, URL cho filter, useState cho local state.
Bảo mật Web: OWASP Top 10 cho Node.js và React
Hướng dẫn bảo mật thực chiến — ngăn chặn SQL injection, XSS, broken authentication, IDOR và security misconfiguration.