Skip to main content

路由

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

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

App Router

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

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

路由配置

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

动态路由

创建 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>