Next.js路由导航完全指南

发布于:2025-05-30 ⋅ 阅读:(17) ⋅ 点赞:(0)

在前端框架(如 React、Vue 等)或移动端开发中,路由系统是实现页面 / 界面导航的核心机制。Next.js 采用 文件系统路由(File System Routing),即根据项目目录结构自动生成路由。

Next.js 目前有两套路由解决方案,Next.js 从 v13.0.0 版本开始引入 App Router,之前的方案称之为“Pages Router”,目前的方案称之为“App Router”,两套路由系统可以相互兼容,Next.js v14+ 默认启用,本文基于 next v15版本说明。

关键区别

特性 Pages Router App Router
目录结构 基于 pages/ 目录 基于 app/ 目录
组件类型 仅支持客户端组件 支持 Server Components(默认)
数据获取 getServerSideProps/getStaticProps 直接在组件中使用 async/await
布局方式 手动实现 Layout 组件 自动支持嵌套布局(layout.js)
文件类型 .js/.jsx/.tsx 新增 .server.jsx/.client.jsx

四种导航方式

Next.js 提供了多种路由导航方式,每种方式都有其特定的使用场景和优势。

1. 组件

是 Next.js 提供的一个内置组件,用于在页面之间进行客户端导航。它扩展了 HTML 的 a 标签,提供了预获取和路由之间的客户端导航功能。这是在 Next.js 中推荐的路由导航方式。

基础使用

import Link from 'next/link';

export default function Page() {
  return <Link href="/dashboard">Dashboard</Link>;
}

动态路由

import Link from 'next/link';

export default function Page() {
  const items = [
    { id: 1, name: 'Item 1' },
    { id: 2, name: 'Item 2' },
  ];

  return (
    <ul>
      {items.map(item => (
        <li key={item.id}>
          <Link href={`/items/${item.id}`}>{item.name}</Link>
        </li>
      ))}
    </ul>
  );
}

获取当前路径名

import { usePathname } from 'next/navigation';

export default function Page() {
  const pathname = usePathname();

  return <div>Current Path: {pathname}</div>;
}

2. useRouter (客户端组件)

允许你以编程方式改变来自客户端组件的路由,这种方式适用于在事件处理函数或异步操作中进行导航。

'use client';

import { useRouter } from 'next/navigation';

export default function Page() {
  const router = useRouter();

  return (
    <button type="button" onClick={() => router.push('/dashboard')}>
      Dashboard
    </button>
  );
}

useRouter 的常用方法:

  • push:在客户端将新地址添加到浏览器历史栈中。
  • replace:在客户端导航时,将现在的访问地址替换成目标地址。
  • refresh:刷新当前路由。
  • prefetch:预获取提供的路由,加快客户端导航速度。
  • back:向后导航到浏览器历史栈中的上一页。
  • forward:向前导航到浏览器历史栈中的下一页。

3. redirect 功能(服务端组件)

redirect 函数用于在服务器组件中进行路由跳转。这种方式通常用于在服务器端根据某些条件重定向用户。

import { redirect } from 'next/navigation'

async function fetchTeam(id: string) {
  const res = await fetch('https://...')
  if (!res.ok) return undefined
  return res.json()
}

export default async function Profile({
  params,
}: {
  params: Promise<{ id: string }>
}) {
  const { id } = await params
  if (!id) {
    redirect('/login')
  }

  const team = await fetchTeam(id)
  if (!team) {
    redirect('/join')
  }

  // ...
}
  • redirect 默认返回 307(临时重定向)状态代码。当在服务器操作中使用时,它会返回 303(请参阅其他),通常用于由于 POST 请求而重定向到成功页面。
  • 如果你想在渲染过程之前重定向,可以使用 next.config.js 或 中间件。
中间件

中间件允许你在请求完成之前运行代码。然后,根据传入的请求,你可以通过重写、重定向、修改请求或响应标头或直接响应来修改响应。

中间件在缓存内容和路由匹配之前运行。

常见应用场景

  • 读取部分传入请求后快速重定向
  • 根据A/B测试或实验重写到不同的页面
  • 修改所有页面或部分页面的标题
  • 拦截请求,实现鉴权、日志

中间件中的 NextResponse

  • redirect 传入请求到不同的 URL
  • rewrite 通过显示给定 URL 进行响应
  • 设置 API 路由,getServerSideProps 和 rewrite 目标的请求标头。
  • 设置响应 cookie
  • 设置响应标头
中间件的重定向应用

1. 鉴权
中间件允许你在请求完成之前运行代码。然后,根据传入请求,使用 NextResponse.redirect 重定向到不同的 URL。如果你想根据条件(例如身份验证、会话管理等)重定向用户或有大量重定向(非登录页验证 token)。

例如,如果用户未通过身份验证,则将用户重定向到 /login 页面:
```
import { NextResponse, NextRequest } from 'next/server'
import { authenticate } from 'auth-provider'

export function middleware(request: NextRequest) {
  const isAuthenticated = authenticate(request)

  // If the user is authenticated, continue as normal
  if (isAuthenticated) {
    return NextResponse.next()
  }

  // Redirect to login page if not authenticated
  return NextResponse.redirect(new URL('/login', request.url))
}

export const config = {
  matcher: '/dashboard/:path*',
}
```
- 中间件在 redirects 之后、next.config.js 中、渲染之前运行。
  1. 拦截请求
export function middleware(request) {
  if (!request.cookies.has('token')) {
    return Response.redirect(new URL('/login', request.url));
  }
}

4. 原生 history API

除了 Next.js 提供的路由功能外,你还可以使用浏览器的原生 History API 进行路由跳转。这种方式适用于需要更细粒度控制路由历史的情况,不会重新加载页面。

export default function Page() {
  return (
    <button type="button" onClick={() => window.history.pushState({}, '', '/dashboard')}>
      Dashboard
    </button>
  );
}

动态路由

Next.js 提供了强大的动态路由功能,允许开发者根据动态参数生成页面。

1. 概念

动态路由允许你根据动态参数生成页面。例如,一个博客网站可能需要为每篇文章生成一个单独的页面,而文章的 ID 是动态的。通过动态路由,你可以使用一个页面模板来处理所有这些动态页面。

2. 创建动态路由

在 Next.js 中,动态路由通过在页面文件名中使用方括号 [] 来定义。例如,如果你有一个页面文件名为 [id].js,那么这个页面将能够处理所有类似 /123、/456 的路径,其中 123 和 456 是动态参数。

pages/
├── posts/
│   └── [id].js
└── users/
    └── [username].js
获取动态参数

在动态路由页面中,你可以通过 useRouter 钩子或 getServerSideProps、getStaticProps 等方法来获取动态参数。

特性 useRouter 钩子 getServerSideProps getStaticProps
使用环境 仅客户端 仅服务端 仅构建时
获取参数方式 const { id } = useRouter().query context.params context.params
数据获取时机 客户端渲染时 每次请求时 构建时
SEO 友好性 较差(客户端渲染) 优秀(服务端渲染) 优秀(静态生成)
性能影响 客户端解析,影响较小 每次请求都执行,影响较大 仅构建时执行,运行时无负担
适用场景 不需要SEO的交互部分 需要实时数据的页面 内容不频繁变化的页面
类型支持 需要手动类型断言 自动推断类型 自动推断类型
静态生成支持 不适用 不适用 支持,需配合 getStaticPaths
访问请求对象 不可访问 可通过 context.req 访问 不可访问
访问响应对象 不可访问 可通过 context.res 访问 不可访问
重定向处理 使用 router.push 可在函数内返回 redirect 对象 可在函数内返回 redirect 对象
重新验证支持 不适用 不适用 支持 revalidate 参数
预渲染行为 客户端渲染 服务端渲染 静态生成
动态路由必需配置 不需要 不需要 需要 getStaticPaths

策略流程图

在这里插入图片描述

并行路由

(未完待续)


网站公告

今日签到

点亮在社区的每一天
去签到