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、动态路由)。

相关推荐
LFly_ice3 小时前
学习React-19-useDebugValue
javascript·学习·react.js
我不是程序媛lisa3 小时前
前端正确处理“文字溢出”的思路与最佳实践
前端·css3
BigTopOne3 小时前
【Fragment】parentFragmentManager , childFragmentManager 区别是什么? 分别在什么场景使用?
前端
岁月宁静3 小时前
Vue3.5 + SSE 构建高可用 AI 聊天交互层 ——chat.js 模块架构与实现
前端·vue.js·人工智能
~无忧花开~3 小时前
JavaScript学习笔记(十七):ES6生成器函数详解
开发语言·前端·javascript·笔记·学习·es6·js
前端 贾公子3 小时前
Vue3 defineModel === 实现原理
前端·javascript·vue.js
电商API_180079052473 小时前
获取淘宝商品视频API接口解析:通过商品链接url获取商品视频item_video
开发语言·爬虫·python·数据挖掘·数据分析
东华帝君3 小时前
五种继承的方式
前端