Next.js App Router服务端渲染与数据获取模式实战

Next.js App Router架构解析

Next.js App Router基于React Server Components(RSC)重新设计了渲染模型。页面组件默认在服务端执行,只有标记了"use client"的组件才在浏览器运行。这种模型让数据获取可以直接在组件内以同步风格编写,无需useEffect或getServerSideProps等API。

App Router的核心概念是布局(layout)和页面(page)的嵌套结构,layout不会在路由切换时重新渲染,page则是路由对应的渲染内容。理解Server Component和Client Component的边界划分,是正确使用App Router的前提。

Server Component数据获取模式

Server Component中直接使用async/await获取数据,框架自动处理请求去重和缓存:

// app/products/page.tsx - Server Component(默认)
export default async function ProductsPage() {
  const products = await fetchProducts();

  return (
    <div>
      <h1>商品列表</h1>
      <ProductGrid products={products} />
    </div>
  );
}

// fetch默认缓存:force-cache
// 添加revalidate实现ISR(增量静态再生)
async function fetchProducts() {
  const res = await fetch("https://api.example.com/products", {
    next: { revalidate: 3600 }
  });
  return res.json();
}

三种渲染模式的选择策略

// 1. 静态生成(SSG):构建时生成,适合内容固定页面
export default function AboutPage() {
  return <div>关于我们 - 静态内容</div>;
}

// 2. 服务端渲染(SSR):每次请求都重新渲染
async function getRealtimeData() {
  const res = await fetch("https://api.example.com/realtime", {
    cache: "no-store"
  });
  return res.json();
}

// 3. 增量静态再生(ISR):静态页面定时更新
async function getBlogPosts() {
  const res = await fetch("https://api.example.com/posts", {
    next: { revalidate: 600 }
  });
  return res.json();
}

选择依据:内容不频繁变选用SSG(营销页、文档);实时数据用SSR(仪表盘、交易页);更新有延迟容忍用ISR(博客、商品页)。

布局嵌套与状态保持

// app/layout.tsx - 根布局
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="zh">
      <body>
        <Navbar />
        <main>{children}</main>
        <Footer />
      </body>
    </html>
  );
}

// app/dashboard/layout.tsx - 仪表盘专属布局
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
  return (
    <div className="flex">
      <Sidebar />
      <div className="flex-1">{children}</div>
    </div>
  );
}

Server与Client组件边界划分

// app/products/ProductFilter.tsx - Client Component
"use client";

import { useState } from "react";

export default function ProductFilter({ categories }: { categories: string[] }) {
  const [selected, setSelected] = useState("all");

  return (
    <div className="flex gap-2">
      {categories.map(cat => (
        <button
          key={cat}
          onClick={() => setSelected(cat)}
          className={selected === cat ? "active" : ""}
        >
          {cat}
        </button>
      ))}
    </div>
  );
}

// app/products/page.tsx - Server Component导入Client组件
import ProductFilter from "./ProductFilter";

export default async function ProductsPage() {
  const { products, categories } = await fetchData();

  return (
    <div>
      <ProductFilter categories={categories} />
      <ProductGrid products={products} />
    </div>
  );
}

边界原则:Server Component可以导入并渲染Client Component,Client Component不能导入Server Component。需要服务端逻辑时,通过props传递数据或使用Route Handler。

并行数据获取优化

// 并行获取(快)- 推荐
async function Page() {
  const [user, orders] = await Promise.all([
    fetchUser(),
    fetchOrders()
  ]);
}

// 更优方案:使用Suspense流式渲染
import { Suspense } from "react";

async function Page() {
  return (
    <div>
      <h1>用户中心</h1>
      <Suspense fallback={<ProfileSkeleton />}>
        <UserProfile />
      </Suspense>
      <Suspense fallback={<OrdersSkeleton />}>
        <UserOrders />
      </Suspense>
    </div>
  );
}

Route Handler替代API Routes

// app/api/webhook/route.ts
import { NextRequest, NextResponse } from "next/server";

export async function POST(request: NextRequest) {
  const body = await request.json();
  const signature = request.headers.get("x-webhook-signature");
  if (!verifySignature(body, signature)) {
    return NextResponse.json({ error: "Invalid signature" }, { status: 401 });
  }
  await processWebhook(body);
  return NextResponse.json({ received: true });
}

// 流式响应(适合AI对话场景)
export async function GET() {
  const stream = new ReadableStream({
    async start(controller) {
      const encoder = new TextEncoder();
      for await (const chunk of aiStream()) {
        controller.enqueue(encoder.encode(chunk));
      }
      controller.close();
    }
  });
  return new Response(stream, {
    headers: { "Content-Type": "text/event-stream" }
  });
}

App Router的渲染模型需要重新理解Server First的设计哲学,将交互边界收缩到最小范围,最大化服务端渲染比例,才能发挥RSC架构的性能优势。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/nextjsapprouter-fu-wu-duan-xuan-ran-yu-shu-ju-huo-qu-mo-shi/

(0)
小编小编
上一篇 12小时前
下一篇 12小时前

相关推荐