{post.title}
{post.excerpt}
Next.js 13 引入了全新的 App Router,基于 React Server Components 构建,为我们提供了更强大和灵活的路由系统。
App Router 使用文件系统来定义路由,每个文件夹代表一个路由段。
```
app/
├── page.tsx // /
├── about/
│ └── page.tsx // /about
├── blog/
│ ├── page.tsx // /blog
│ └── [slug]/
│ └── page.tsx // /blog/[slug]
└── dashboard/
├── layout.tsx
├── page.tsx // /dashboard
└── settings/
└── page.tsx // /dashboard/settings
```
App Router 定义了几个特殊文件:
每个应用都需要一个根布局:
```tsx
// app/layout.tsx
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
可以为特定路由段创建嵌套布局:
```tsx
// app/dashboard/layout.tsx
export default function DashboardLayout({
children,
}: {
children: React.ReactNode
}) {
return (
默认情况下,App Router 中的组件都是 Server Components:
```tsx
// app/blog/page.tsx
async function getBlogPosts() {
const res = await fetch('https://api.example.com/posts')
return res.json()
}
export default async function BlogPage() {
const posts = await getBlogPosts()
return (
{post.excerpt}
可以并行获取多个数据源:
```tsx
async function getUser(id: string) {
const res = await fetch(/api/users/${id}
)
return res.json()
}
async function getUserPosts(id: string) {
const res = await fetch(/api/users/${id}/posts
)
return res.json()
}
export default async function UserPage({ params }: { params: { id: string } }) {
// 并行获取数据
const [user, posts] = await Promise.all([
getUser(params.id),
getUserPosts(params.id)
])
return (
使用方括号创建动态路由:
```tsx
// app/blog/[slug]/page.tsx
export default function BlogPost({ params }: { params: { slug: string } }) {
return
使用 [...slug]
捕获所有路由段:
```tsx
// app/docs/[...slug]/page.tsx
export default function DocsPage({ params }: { params: { slug: string[] } }) {
return
使用括号创建路由组,不影响 URL 结构:
```
app/
├── (marketing)/
│ ├── about/
│ │ └── page.tsx
│ └── contact/
│ └── page.tsx
└── (dashboard)/
├── analytics/
│ └── page.tsx
└── settings/
└── page.tsx
```
在根目录创建 middleware.ts
文件:
```tsx
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
// 检查认证
const token = request.cookies.get('token')
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
export const config = {
matcher: ['/dashboard/:path*']
}
```
默认使用 Server Components,只在需要交互时使用 Client Components:
```tsx
// Server Component (默认)
async function ServerComponent() {
const data = await fetchData()
return
// Client Component (需要 'use client')
'use client'
function ClientComponent() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}
}
```
使用 fetch
的缓存功能:
```tsx
// 缓存数据
async function getData() {
const res = await fetch('https://api.example.com/data', {
cache: 'force-cache' // 强制缓存
})
return res.json()
}
// 重新验证数据
async function getRealtimeData() {
const res = await fetch('https://api.example.com/data', {
next: { revalidate: 60 } // 60秒后重新验证
})
return res.json()
}
```
创建错误边界:
```tsx
// app/error.tsx
'use client'
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
return (
App Router 为 Next.js 应用带来了:
掌握这些概念和最佳实践,你就能充分利用 App Router 的强大功能!
```