Web典型路由结构之Next.js (App Router, v13+) )(文件系统驱动的路由:File-based Routing)声明式路由:文件即路由

文章目录

  • [📂 项目结构 (基于 `app` 目录)](#📂 项目结构 (基于 app 目录))
  • [🔑 核心文件实现](#🔑 核心文件实现)
    • [1. 根布局 (`app/layout.tsx`)](#1. 根布局 (app/layout.tsx))
    • [2. 首页 (`app/page.tsx`)](#2. 首页 (app/page.tsx))
    • [3. 项目列表页 (`app/projects/page.tsx`)](#3. 项目列表页 (app/projects/page.tsx))
    • [4. 项目详情页 (`app/projects/projectId/page.tsx`)](#4. 项目详情页 (app/projects/[projectId]/page.tsx))
    • [5. 设置页权限控制 (`app/settings/layout.tsx`)](#5. 设置页权限控制 (app/settings/layout.tsx))
    • [6. 登录页 (`app/signin/page.tsx`)](#6. 登录页 (app/signin/page.tsx))
    • [7. 404 页面 (`app/not-found.tsx`)](#7. 404 页面 (app/not-found.tsx))
    • [8. 错误处理 (`app/error.tsx`)](#8. 错误处理 (app/error.tsx))
  • [🌟 与 React Router v6 的关键差异](#🌟 与 React Router v6 的关键差异)
  • [✅ 为什么 Next.js 的设计更优?](#✅ 为什么 Next.js 的设计更优?)
    • [1. **无需维护路由配置**:文件系统即路由,新增页面只需创建文件](#1. 无需维护路由配置:文件系统即路由,新增页面只需创建文件)
    • [2. **自动代码分割**:按路由自动分割代码块(无需 `lazy`)](#2. 自动代码分割:按路由自动分割代码块(无需 lazy))
    • [3. **权限控制更合理**:在布局层处理(避免页面加载后再重定向)](#3. 权限控制更合理:在布局层处理(避免页面加载后再重定向))
    • [4. **开发体验更好**:文件命名即路由,直观易维护](#4. 开发体验更好:文件命名即路由,直观易维护)
    • [5. **内置 404/错误处理**:`not-found.tsx` 和 `error.tsx` 自动生效](#5. 内置 404/错误处理not-found.tsxerror.tsx 自动生效)
    • [> 💡 提示:Next.js 的权限控制**不要**在 `page.tsx` 中做(会先加载页面再重定向),必须放在 `layout.tsx` 中(如 `settings/layout.tsx`)。](#> 💡 提示:Next.js 的权限控制不要page.tsx 中做(会先加载页面再重定向),必须放在 layout.tsx 中(如 settings/layout.tsx)。)
  • [🚀 运行效果](#🚀 运行效果)
  • [> ✨ **关键总结**:Next.js 的路由是**声明式**的(文件即路由),而 React Router 是**配置式**的(需要手动写路由表)。Next.js 的设计让路由与文件结构绑定,大幅降低维护成本,同时内置了最佳实践(权限、404、动态路由)。](#> ✨ 关键总结:Next.js 的路由是声明式的(文件即路由),而 React Router 是配置式的(需要手动写路由表)。Next.js 的设计让路由与文件结构绑定,大幅降低维护成本,同时内置了最佳实践(权限、404、动态路由)。)

以下是 Next.js (App Router, v13+) ( SSR)的典型路由结构实现,与 React Router v6( CSR) 的配置式路由不同,Next.js 采用 文件系统驱动的路由 (File-based Routing),无需显式编写路由配置文件:


📂 项目结构 (基于 app 目录)

bash 复制代码
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)

ts 复制代码
// 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)

ts 复制代码
// 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)

ts 复制代码
// 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)

ts 复制代码
// 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)

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

ts 复制代码
// 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)

ts 复制代码
// 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)

ts 复制代码
// 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)

ts 复制代码
// 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 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.tsxerror.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、动态路由)。

相关推荐
Pedantic9 小时前
SwiftUI 手势层级(Gesture Hierarchy)详解
前端
飘尘9 小时前
前端转型全栈(Java后端)的快速上手指引
前端·后端·全栈
一颗烂土豆10 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
浏览器工程师11 小时前
AI Agent 接浏览器任务,先别让它一路点到底
前端·后端
雨季mo浅忆11 小时前
VSCode自动格式化三要素
前端
爱勇宝11 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员
kyriewen12 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
user205855615181314 小时前
Windows 项目安装时报 `node-sass` 错误,如何快速处理
前端
LiaCode14 小时前
Redis 在生产项目的使用
前端·后端