路由
Next.js 使用文件系统路由。包括:App Router 和 Pages Router
虽然可以在同一个项目中使用两种路由,但 app 中的路由将优先于 pages。建议在新项目中只使用一种路由,以避免混淆。推荐使用 App Router
App Router
1、创建一个 app
文件夹,然后添加 layout.tsx
和 page.tsx
文件。当用户访问应用程序的根目录 /
时,将呈现这些内容。
2、在 layout.tsx 中创建一个带有所需 html 和 body 标签的根布局:
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
3、创建一个包含一些初始内容的首页:
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>