跳到主要内容

路由

Next.js 使用文件系统路由。包括:App Router 和 Pages Router

虽然可以在同一个项目中使用两种路由,但 app 中的路由将优先于 pages。建议在新项目中只使用一种路由,以避免混淆。官方推荐使用 App Router

Pages Router

1、创建一个 pages 文件夹,在 pages 文件夹中添加一个 index.tsx 文件,这就是首页 /

export default function Page() {
return <h1>Hello, Next.js!</h1>;
}

2、在 pages 中添加一个 _app.tsx 文件用来定义全局布局:

import type { AppProps } from 'next/app';

export default function App({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />;
}

3、在 pages 中添加一个 _document.tsx 文件来控制来自服务器的初始响应:

import { Html, Head, Main, NextScript } from 'next/document';

export default function Document() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}

App Router

目录解析

src/
└── app
├── page.tsx
├── layout.tsx
├── template.tsx
├── loading.tsx
├── error.tsx
├── not-found.tsx
└── dashboard
└── components
└── page.tsx
└── settings
└── page.tsx
  • app/page.tsx 对应路由 /
  • app/dashboard/page.tsx 对应路由 /dashboard
  • app/dashboard/settings/page.js 对应路由/dashboard/settings
  • app/dashboard/components 目录下因为没有 page.tsx 文件,所以没有对应的路由。这种文件可以用来存放组件、样式、图片或者其他文件。

注意:.js.jsx.tsx文件都是支持的

特殊文件

Next.js 约定了一些特殊文件,这些文件可以是.js.jsx.tsx

文件描述
layout共享的布局
page页面,可公开访问
loading加载状态
error错误处理
not-found404 页面

示例

1、创建一个 app 文件夹,然后添加 layout.tsxpage.tsx 文件。当用户访问应用程序的根目录 / 时,将呈现这些内容。

2、在 layout.tsx 中创建一个带有所需 html 和 body 标签的根布局:

app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}

3、创建一个包含一些初始内容的首页:

app/page.tsx
export default function Page() {
return <h1>Hello, Next.js!</h1>;
}

根布局

使用 create-next-app 默认创建的 layout.js 代码如下:

import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import './globals.css';

const inter = Inter({ subsets: ['latin'] });

export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app'
};

export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
);
}
  1. app 目录必须包含根布局
  2. 根布局必须包含 html 和 body 标签,其他布局不能包含这些标签
  3. 可以通过 Metadata API 配置元数据
  4. 根布局默认是服务端组件,且不能设置为客户端组件
  5. 可以使用路由组创建多个根布局

路由配置

Next.js 使用基于文件系统的路由器,其中文件夹用于定义路由。

嵌套路由:将文件夹相互嵌套。如创建 app/users/new/page.tsx,然后可以通过 /users/new 访问。

注意:必须要有 page.tsx 文件,否则无法公开访问。page 的后缀可以是 .js.jsx.tsx

路由导航

路由导航有 4 种方式:

  • 使用 Link 组件
  • useRouter (客户端组件)
  • redirect (服务端组件)
  • 浏览器的 History API

1、使用 Link 组件

如果使用 a 标签,会重新加载整个页面。使用 Link 组件,会局部刷新。

在生产环境中,每当 Link 组件出现在浏览器的视口中时,Next.js 会自动在后台预取链接路由的代码。当用户点击链接时,目标页面的代码已经在后台加载。

import Link from 'next/link';

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

可以使用 usePathname() 来获取当前路径,但是不能在服务端使用。

'use client';

import { usePathname } from 'next/navigation';
import Link from 'next/link';

export function Links() {
const pathname = usePathname();

return (
<Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/">
Home
</Link>
);
}

2、useRouter (客户端组件)

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>
);
}

路由参数

useSearchParams 访问当前 URL 的参数。如 /dashboard/invoices?page=1&query=pending 的结果是:{ page: '1', query: 'pending' }

usePathname 读取当前 URL 的路径名。例如,对于路由/dashboard/invoices,将返回 '/dashboard/invoices'

'use client';

import { useEffect } from 'react';
import { usePathname, useSearchParams } from 'next/navigation';

export default function NavigationEvents() {
const pathname = usePathname();
const searchParams = useSearchParams();

useEffect(() => {
const url = `${pathname}?${searchParams}`;
console.log(url);
}, [pathname, searchParams]);

return null;
}

动态路由

[folderName]

使用动态路由,需要将文件夹的名字用方括号括住,比如 [id][slug]。这个路由的名字会传递给 params 对象。

创建 app/users/[id]/page.tsx

export default function Page({ params }: { params: { id: string } }) {
return <div>userID: {params.id}</div>;
}

app/users/page.tsx 中跳转,并传递参数:

<Link href="/users/1">user1</Link>
<Link href="/users/2">user2</Link>

[...folderName]