📚 现代前端开发 目录
阶段3:React
第 21 / 35 课

服务端渲染:Next.js

React的全栈框架

📖 核心概念

💻 代码实现

Next.js App Router ✅ tsx
// app/layout.tsx - 根布局 (Server Component)
import type { Metadata } from 'next';
import './globals.css';

export const metadata: Metadata = {
  title: { default: '我的应用', template: '%s | 我的应用' },
  description: '使用Next.js构建的现代应用',
  keywords: ['React', 'Next.js', 'TypeScript'],
};

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="zh-CN">
      <body>{children}</body>
    </html>
  );
}

// app/page.tsx - 首页 (Server Component)
async function HomePage() {
  // 服务端直接获取数据,无需useEffect
  const posts = await fetch('https://api.example.com/posts', {
    next: { revalidate: 3600 }, // ISR: 1小时后重新验证
  }).then(r => r.json());

  return (
    <main>
      <h1>最新文章</h1>
      {posts.map((post: any) => (
        <article key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.excerpt}</p>
        </article>
      ))}
    </main>
  );
}

// app/blog/[slug]/page.tsx - 动态路由 (SSG)
interface BlogPostProps { params: { slug: string } }

// 生成静态路径
export async function generateStaticParams() {
  const posts = await fetch('https://api.example.com/posts').then(r => r.json());
  return posts.map((post: any) => ({ slug: post.slug }));
}

// 生成元数据
export async function generateMetadata({ params }: BlogPostProps) {
  const post = await fetch(\`https://api.example.com/posts/\${params.slug}\`).then(r => r.json());
  return {
    title: post.title,
    description: post.excerpt,
    openGraph: { title: post.title, description: post.excerpt },
  };
}

export default async function BlogPost({ params }: BlogPostProps) {
  const post = await fetch(\`https://api.example.com/posts/\${params.slug}\`, {
    next: { revalidate: 3600 },
  }).then(r => r.json());

  return (
    <article>
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
    </article>
  );
}
Server Actions与Client Components ✅ tsx
// app/actions.ts - Server Actions
'use server';

import { revalidatePath } from 'next/cache';
import { redirect } from 'next/navigation';
import { z } from 'zod';

const createPostSchema = z.object({
  title: z.string().min(1),
  content: z.string().min(10),
});

export async function createPost(formData: FormData) {
  const data = createPostSchema.parse({
    title: formData.get('title'),
    content: formData.get('content'),
  });

  await db.post.create({ data });

  revalidatePath('/blog'); // 刷新博客页面缓存
  redirect('/blog'); // 重定向到博客列表
}

export async function deletePost(id: string) {
  await db.post.delete({ where: { id } });
  revalidatePath('/blog');
}

// app/blog/create/page.tsx - 表单使用Server Action
import { createPost } from '@/app/actions';

export default function CreatePostPage() {
  return (
    <form action={createPost} className="form">
      <input name="title" placeholder="标题" required />
      <textarea name="content" placeholder="内容" required />
      <button type="submit">发布文章</button>
    </form>
  );
}

// components/PostEditor.tsx - Client Component
'use client';

import { useTransition } from 'react';
import { deletePost } from '@/app/actions';

export function DeleteButton({ postId }: { postId: string }) {
  const [isPending, startTransition] = useTransition();

  return (
    <button
      disabled={isPending}
      onClick={() => startTransition(() => deletePost(postId))}
    >
      {isPending ? '删除中...' : '删除'}
    </button>
  );
}

// app/api/route.ts - API Routes
import { NextRequest, NextResponse } from 'next/server';

export async function GET(request: NextRequest) {
  const searchParams = request.nextUrl.searchParams;
  const page = searchParams.get('page') || '1';

  const posts = await db.post.findMany({
    skip: (Number(page) - 1) * 10,
    take: 10,
  });

  return NextResponse.json(posts);
}

export async function POST(request: NextRequest) {
  const body = await request.json();
  const post = await db.post.create({ data: body });
  return NextResponse.json(post, { status: 201 });
}

🎯 练习任务

🏆 成就解锁
Next.js开发者 — 掌握Next.js全栈开发,构建高性能的React应用