返回博客

Next.js 16 实战

Next.js 16 于 2026 年 3 月正式发布,带来了许多重大更新。作为目前最流行的 React 全栈框架,Next.js 16 进一步简化了开发体验,提升了性能。

本文通过一个完整的博客系统示例,带你掌握 Next.js 16 的核心特性。

核心特性:App Router 稳定版、Server Actions 正式支持、Turbopack 默认启用、部分预渲染(PPR)

环境准备

系统要求

创建项目

# 使用 pnpm(推荐)
pnpm create next-app@latest my-blog

# 选择配置:
# - TypeScript: Yes
# - ESLint: Yes
# - Tailwind CSS: Yes
# - `src/` directory: Yes
# - App Router: Yes
# - Turbopack: Yes (默认启用)

cd my-blog
pnpm dev
Next.js 16 变化:Turbopack 现在是默认选项,开发速度比 Webpack 快 53%。

项目结构

my-blog/
├── src/
│   ├── app/                    # App Router 路由
│   │   ├── layout.tsx          # 根布局
│   │   ├── page.tsx            # 首页
│   │   ├── blog/
│   │   │   ├── page.tsx        # 博客列表
│   │   │   └── [slug]/
│   │   │       └── page.tsx    # 博客详情
│   │   └── api/                # API 路由
│   ├── components/             # React 组件
│   ├── lib/                    # 工具函数
│   └── styles/                 # 全局样式
├── public/                     # 静态资源
└── package.json

核心特性实战

1. App Router 基础

Next.js 16 中 App Router 已经是稳定版本,推荐使用。

// src/app/layout.tsx
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    
      
        
        {children}
      
    
  )
}
关键概念
  • layout.tsx:布局组件,嵌套渲染,状态保持
  • page.tsx:页面组件,路由终点
  • loading.tsx:加载状态
  • error.tsx:错误边界

2. Server Components(默认)

Next.js 16 中,所有组件默认都是服务端组件(RSC)。

// src/app/blog/page.tsx - 服务端组件
import { getPosts } from '@/lib/db'

export default async function BlogPage() {
  const posts = await getPosts() // 直接异步获取数据
  
  return (
    

博客列表

{posts.map(post => (

{post.title}

{post.excerpt}

))}
) }
注意:服务端组件不能使用 useState、useEffect 等客户端 Hook。

3. Client Components

需要交互时使用客户端组件:

'use client'

// src/components/SearchBox.tsx
import { useState } from 'react'

export function SearchBox() {
  const [query, setQuery] = useState('')
  
  return (
     setQuery(e.target.value)}
      placeholder="搜索文章..."
    />
  )
}

4. Server Actions(数据突变)

Next.js 16 中 Server Actions 正式支持,可以直接在表单中调用服务端函数。

// src/app/blog/actions.ts
'use server'

import { revalidatePath } from 'next/cache'

export async function createPost(formData: FormData) {
  const title = formData.get('title') as string
  const content = formData.get('content') as string
  
  // 保存到数据库
  await db.post.create({ title, content })
  
  // 重新验证缓存
  revalidatePath('/blog')
}

// src/app/blog/new/page.tsx
import { createPost } from './actions'

export default function NewPostPage() {
  return (