以下是 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           # /projects 页面
│   └── [projectId]/       # 动态路由
│       └── page.tsx       # /projects/:projectId
├── settings/
│   ├── layout.tsx         # 设置页布局 (用于权限控制)
│   └── page.tsx           # /settings 页面
├── signin/
│   └── page.tsx           # /signin 页面
├── not-found.tsx          # 404 页面 (自定义)
└── error.tsx              # 全局错误页面

核心文件实现

1. 根布局 (app/layout.tsx)

// app/layout.tsx
// 导入全局CSS样式文件(在Next.js中,全局样式通常放在这里)
import './globals.css'
// 导入Google字体(Inter字体),用于设置页面的字体
import { Inter } from 'next/font/google'
// 使用Inter字体,指定子集为拉丁文(支持大部分英文字符)
const inter = Inter({ subsets: ['latin'] })
// 设置页面的元数据(标题、描述等,用于SEO优化)
export const metadata = {
title: 'Next.js App', // 页面标题
description: 'Generated by Next.js', // 页面描述
}
// 根布局组件,所有页面共享这个布局
export default function RootLayout({
children,
}: {
children: React.ReactNode // 代表子组件(页面内容)
}) {
// 返回HTML结构,其中包含页面的根元素
return (
<html lang="en"> // 指定页面语言为英语
  <body className={inter.className}> // 将字体类名应用到body,使页面使用Inter字体
    <header>My App Header</header> // 页面头部(通常包含导航栏)
      {children} // 这里是子组件(当前页面的内容)将被渲染在这里
      <footer>Footer</footer> // 页面底部
        </body>
          </html>
            )
            }

2. 首页 (app/page.tsx)

// 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)

// app/projects/page.tsx
// 项目列表页面组件
export default function Projects() {
// 返回项目列表页面的内容
return (
<div> // 容器div
  <h1>Projects List</h1> // 项目列表标题
    <ul> // 无序列表
      <li><a href="/projects/1">Project 1</a></li> // 项目1的链接
        <li><a href="/projects/2">Project 2</a></li> // 项目2的链接
          </ul>
            </div>
              )
              }

4. 项目详情页 (app/projects/[projectId]/page.tsx)

// app/projects/[projectId]/page.tsx
// 项目详情页面组件,用于显示特定项目的详细信息
import { notFound } from 'next/navigation' // 用于触发404页面的函数
// 项目详情页面组件,接收参数(动态路由参数)
export default function ProjectDetail({ params }: { params: { projectId: string } }) {
// 模拟项目数据(实际应用中会从API获取)
const validProjects = ['1', '2', '3']
// 检查传入的projectId是否有效
if (!validProjects.includes(params.projectId)) {
notFound() // 如果无效,触发404页面
}
// 返回项目详情页面
return (
<div> // 容器div
  <h1>Project Detail: {params.projectId}</h1> // 显示项目ID
    <a href="/projects">Back to Projects</a> // 返回项目列表的链接
      </div>
        )
        }

5. 设置页权限控制 (app/settings/layout.tsx)

关键点:权限检查放在布局层(避免页面加载后再重定向)

// app/settings/layout.tsx
import { cookies } from 'next/headers' // 用于操作HTTP cookies
import { redirect } from 'next/navigation' // 用于重定向页面
// 设置页布局组件,用于权限控制
export default function SettingsLayout({
children,
}: {
children: React.ReactNode // 代表子组件(设置页面内容)
}) {
// 从cookies中获取token(用于用户认证)
const token = cookies().get('token')?.value
// 如果没有token(用户未登录),重定向到登录页
// encodeURIComponent确保URL安全
if (!token) {
redirect(`/signin?next=${encodeURIComponent('/settings')}`)
}
// 如果有token,渲染设置页面内容
return (
<div>
  <h2>Settings</h2> // 设置页面标题
    {children} // 渲染子组件(实际的设置内容)
    </div>
      )
      }

6. 登录页 (app/signin/page.tsx)

// app/signin/page.tsx
import { cookies } from 'next/headers' // 用于操作HTTP cookies
import { redirect } from 'next/navigation' // 用于重定向页面
// 登录页面组件
export default function SignIn() {
// 模拟登录逻辑的函数
const handleLogin = () => {
// 设置cookie(存储token)
cookies().set('token', 'dummy_token')
// 从cookies中获取重定向路径(如果之前访问的是受保护页面)
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)

// app/not-found.tsx
// 404页面组件(当请求的页面不存在时显示)
export default function NotFound() {
return (
<main> // 主要内容区域
  <h1>404 - Page Not Found</h1> // 404标题
    <a href="/">Go Home</a> // 返回首页的链接
      </main>
        )
        }

8. 错误处理 (app/error.tsx)

// app/error.tsx
import { notFound } from 'next/navigation' // 用于触发404页面的函数
// 错误处理页面组件
export default function Error() {
return (
<main> // 主要内容区域
  <h1>Something went wrong</h1> // 错误提示
    <button onClick={() => notFound()}>Go to 404</button> // 点击按钮跳转到404页面
      </main>
        )
        }

与 React Router v6 的关键差异

特性React Router v6Next.js (App Router)
路由定义显式配置文件 (routes.tsx)文件系统自动映射 (app/ 目录)
布局通过 children 嵌套layout.tsx 文件 (自动继承)
权限控制高阶组件 (withAuth)layout.tsx 中直接重定向
动态路由:param 语法 (/projects/:id)[param] 语法 (/projects/[id])
404 页面* 通配符 + errorElementnot-found.tsx 文件
懒加载手动 lazy + Suspense自动按需加载 (无需配置)
重定向redirect 函数 (路由配置中)redirect 函数 (在 layout.tsx/page.tsx 中)

✅ 为什么 Next.js 的设计更优?

1. 无需维护路由配置:文件系统即路由,新增页面只需创建文件

2. 自动代码分割:按路由自动分割代码块(无需 lazy

3. 权限控制更合理:在布局层处理(避免页面加载后再重定向)

4. 开发体验更好:文件命名即路由,直观易维护

5. 内置 404/错误处理not-found.tsxerror.tsx 自动生效

> 提示:Next.js 的权限控制不要page.tsx 中做(会先加载页面再重定向),必须放在 layout.tsx 中(如 settings/layout.tsx)。


运行效果

URL对应文件效果
/app/page.tsx首页
/projectsapp/projects/page.tsx项目列表
/projects/123app/projects/[projectId]/page.tsx项目详情 (动态参数)
/settingsapp/settings/layout.tsx + page.tsx受保护设置页 (需登录)
/signinapp/signin/page.tsx登录页
/non-existentapp/not-found.tsx自定义 404 页面

> ✨ 关键总结:Next.js 的路由是声明式的(文件即路由),而 React Router 是配置式的(需要手动写路由表)。Next.js 的设计让路由与文件结构绑定,大幅降低维护成本,同时内置了最佳实践(权限、404、动态路由)。

posted on 2025-10-14 12:55  ycfenxi  阅读(0)  评论(0)    收藏  举报