文章目录
- 项目结构 (基于 `app` 目录)
- 核心文件实现
- 1. 根布局 (`app/layout.tsx`)
- 2. 首页 (`app/page.tsx`)
- 3. 项目列表页 (`app/projects/page.tsx`)
- 4. 项目详情页 (`app/projects/[projectId]/page.tsx`)
- 5. 设置页权限控制 (`app/settings/layout.tsx`)
- 6. 登录页 (`app/signin/page.tsx`)
- 7. 404 页面 (`app/not-found.tsx`)
- 8. 错误处理 (`app/error.tsx`)
- 与 React Router v6 的关键差异
- ✅ 为什么 Next.js 的设计更优?
- 1. **无需维护路由配置**:文件系统即路由,新增页面只需创建文件
- 2. **自动代码分割**:按路由自动分割代码块(无需 `lazy`)
- 3. **权限控制更合理**:在布局层处理(避免页面加载后再重定向)
- 4. **开发体验更好**:文件命名即路由,直观易维护
- 5. **内置 404/错误处理**:`not-found.tsx` 和 `error.tsx` 自动生效
- > 提示:Next.js 的权限控制**不要**在 `page.tsx` 中做(会先加载页面再重定向),必须放在 `layout.tsx` 中(如 `settings/layout.tsx`)。
- 运行效果
- > ✨ **关键总结**:Next.js 的路由是**声明式**的(文件即路由),而 React Router 是**配置式**的(需要手动写路由表)。Next.js 的设计让路由与文件结构绑定,大幅降低维护成本,同时内置了最佳实践(权限、404、动态路由)。
以下是 Next.js (App Router, v13+) (
SSR)的典型路由结构实现,与 React Router v6(
CSR) 的配置式路由不同,Next.js 采用
文件系统驱动的路由(File-based Routing),无需显式编写路由配置文件:
项目结构 (基于 app 目录)
app/
├── layout.tsx
├── page.tsx
├── projects/
│ ├── layout.tsx
│ ├── page.tsx
│ └── [projectId]/
│ └── page.tsx
├── settings/
│ ├── layout.tsx
│ └── page.tsx
├── signin/
│ └── page.tsx
├── not-found.tsx
└── error.tsx
核心文件实现
1. 根布局 (app/layout.tsx)
import './globals.css'
import { Inter } from 'next/font/google'
const inter = Inter({ subsets: ['latin'] })
export const metadata = {
title: 'Next.js App',
description: 'Generated by Next.js',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body className={inter.className}>
<header>My App Header</header>
{children}
<footer>Footer</footer>
</body>
</html>
)
}
2. 首页 (app/page.tsx)
export default function Home() {
return (
<main>
<h1>Welcome to Home</h1>
<a href="/projects">Go to Projects</a>
</main>
)
}
3. 项目列表页 (app/projects/page.tsx)
export default function Projects() {
return (
<div>
<h1>Projects List</h1>
<ul>
<li><a href="/projects/1">Project 1</a></li>
<li><a href="/projects/2">Project 2</a></li>
</ul>
</div>
)
}
4. 项目详情页 (app/projects/[projectId]/page.tsx)
import { notFound } from 'next/navigation'
export default function ProjectDetail({ params }: { params: { projectId: string } }) {
const validProjects = ['1', '2', '3']
if (!validProjects.includes(params.projectId)) {
notFound()
}
return (
<div>
<h1>Project Detail: {params.projectId}</h1>
<a href="/projects">Back to Projects</a>
</div>
)
}
5. 设置页权限控制 (app/settings/layout.tsx)
关键点:权限检查放在布局层(避免页面加载后再重定向)
import { cookies } from 'next/headers'
import { redirect } from 'next/navigation'
export default function SettingsLayout({
children,
}: {
children: React.ReactNode
}) {
const token = cookies().get('token')?.value
if (!token) {
redirect(`/signin?next=${encodeURIComponent('/settings')}`)
}
return (
<div>
<h2>Settings</h2>
{children}
</div>
)
}
6. 登录页 (app/signin/page.tsx)
import { cookies } from 'next/headers'
import { redirect } from 'next/navigation'
export default function SignIn() {
const handleLogin = () => {
cookies().set('token', 'dummy_token')
const next = cookies().get('next')?.value || '/'
redirect(next)
}
return (
<div>
<h1>Login</h1>
<button onClick={handleLogin}>Sign In</button>
</div>
)
}
7. 404 页面 (app/not-found.tsx)
export default function NotFound() {
return (
<main>
<h1>404 - Page Not Found</h1>
<a href="/">Go Home</a>
</main>
)
}
8. 错误处理 (app/error.tsx)
import { notFound } from 'next/navigation'
export default function Error() {
return (
<main>
<h1>Something went wrong</h1>
<button onClick={() => notFound()}>Go to 404</button>
</main>
)
}
与 React Router v6 的关键差异
| 特性 | React Router v6 | Next.js (App Router) |
|---|
| 路由定义 | 显式配置文件 (routes.tsx) | 文件系统自动映射 (app/ 目录) |
| 布局 | 通过 children 嵌套 | layout.tsx 文件 (自动继承) |
| 权限控制 | 高阶组件 (withAuth) | 在 layout.tsx 中直接重定向 |
| 动态路由 | :param 语法 (/projects/:id) | [param] 语法 (/projects/[id]) |
| 404 页面 | * 通配符 + errorElement | not-found.tsx 文件 |
| 懒加载 | 手动 lazy + Suspense | 自动按需加载 (无需配置) |
| 重定向 | redirect 函数 (路由配置中) | redirect 函数 (在 layout.tsx/page.tsx 中) |
✅ 为什么 Next.js 的设计更优?
1. 无需维护路由配置:文件系统即路由,新增页面只需创建文件
2. 自动代码分割:按路由自动分割代码块(无需 lazy)
3. 权限控制更合理:在布局层处理(避免页面加载后再重定向)
4. 开发体验更好:文件命名即路由,直观易维护
5. 内置 404/错误处理:not-found.tsx 和 error.tsx 自动生效
> 提示:Next.js 的权限控制不要在 page.tsx 中做(会先加载页面再重定向),必须放在 layout.tsx 中(如 settings/layout.tsx)。
运行效果
| URL | 对应文件 | 效果 |
|---|
/ | app/page.tsx | 首页 |
/projects | app/projects/page.tsx | 项目列表 |
/projects/123 | app/projects/[projectId]/page.tsx | 项目详情 (动态参数) |
/settings | app/settings/layout.tsx + page.tsx | 受保护设置页 (需登录) |
/signin | app/signin/page.tsx | 登录页 |
/non-existent | app/not-found.tsx | 自定义 404 页面 |
> ✨ 关键总结:Next.js 的路由是声明式的(文件即路由),而 React Router 是配置式的(需要手动写路由表)。Next.js 的设计让路由与文件结构绑定,大幅降低维护成本,同时内置了最佳实践(权限、404、动态路由)。