Next.js 使用基于文件系统的路由,这意味着您可以使用文件夹和文件来定义路由。本页面将指导您如何创建布局和页面,以及如何在它们之间建立链接
创建 Page
页面是在特定路由上渲染的 UI。要创建页面,请在 app
目录中添加一个 page
文件,并默认导出一个 React 组件。例如,要创建索引页 (/
):
创建 Layout
布局是多个页面之间共享的 UI。导航时,布局会保留状态、保持交互性,并且不会重新渲染
你可以通过从 layout
文件默认导出 React 组件来定义布局。该组件应该接受 children
属性,该属性可以是页面或其他布局
例如,要创建接受索引页作为子页的布局,请在 app
目录中添加 layout
文件:
// app/layout.tsx
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{/* Layout UI */}
{/* Place children where you want to render a page or nested layout */}
<main>{children}</main>
</body>
</html>
)
}
上面的布局称为根布局,因为它定义在 app
目录的根目录下。根布局是必需的,并且必须包含 html
和 body
标签
创建嵌套路线 (nested route)
嵌套路由是由多个 URL 段组成的路由。例如,/blog/[slug]
路由由三个段组成:
/
(Root Segment)blog
(Segment)[slug]
(Leaf Segment)
在 Next.js 中:
- 文件夹用于定义映射到 URL 段的路由段
- 文件(如
page
和layout
)用于创建为某个片段显示的 UI
要创建嵌套路由,您可以将文件夹嵌套在一起。例如,要为 /blog
添加路由,请在 app
目录中创建一个名为 blog
文件夹。然后,要使 /blog
可公开访问,请添加一个 page.tsx
文件
您可以继续嵌套文件夹来创建嵌套路由。例如,要为特定博客文章创建路由,请在 blog
中创建一个新的 [slug]
文件夹并添加一个 page
文件
将文件夹名称括在方括号中(例如 [slug]
)会创建一个动态路由段,用于根据数据生成多个页面,例如博客文章、产品页面等
嵌套布局 (Nesting layouts)
默认情况下,文件夹层次结构中的布局也是嵌套的,这意味着它们通过其 children
属性包裹子布局。您可以通过在特定的路由段(文件夹)内添加 layout
来嵌套布局
例如,要为 /blog
路由创建布局,请在 blog
文件夹中添加一个新的 layout
文件
如果您要组合上述两个布局,根布局 (app/layout.js
) 将包装博客布局 (app/blog/layout.js
),后者将包装博客 (app/blog/page.js
) 和博客文章页面 (app/blog/[slug]/page.js
)
创建动态路由段 (dynamic segment)
动态路由段允许您创建基于数据生成的路由。例如,您无需为每篇博客文章手动创建路由,而是可以创建一个动态路由段,根据博客文章数据生成路由
要创建动态路由段,请将片段(文件夹)名称括在方括号中:[segmentName]
。例如,在 app/blog/[slug]/page.tsx
路由中, [slug]
就是动态路由段
// app/blog/[slug]/page.tsx
export default async function BlogPostPage({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params
const post = await getPost(slug)
return (
<div>
<h1>{post.title}</h1>
<p>{post.content}</p>
</div>
)
}
动态路由段的 layout.js
等文件都是能获取到 params
props 的
Rendering with search params
在服务器组件 Page 中,可以使用 searchParams
属性访问搜索参数:
// app/page.tsx
export default async function Page({ searchParams }: { searchParams: Promise<{ [key: string]: string | string[] | undefined }> }) {
const filters = (await searchParams).filters
}
使用 searchParams
会使您的页面进入动态渲染,因为它需要传入请求来读取搜索参数
客户端组件可以使用 useSearchParams
钩子读取搜索参数
何时使用?
- 当您需要搜索参数来加载页面数据(例如分页、从数据库过滤)时
- 当搜索参数仅在客户端使用时使用
useSearchParams
(例如,过滤已通过 props 加载的列表) - 作为一项小优化,您可以在回调或事件处理程序中使用
new URLSearchParams(window.location.search)
来读取搜索参数,而无需触发重新渲染
页面之间的链接
您可以使用 <Link>
组件在路由之间导航。<Link>
是一个内置的 Next.js 组件,它扩展了 HTML <a>
标签以提供预取和客户端导航
例如,要生成博客文章列表,请从 next/link
导入 <Link>
,并将 href
属性传递给组件:
// app/ui/post.tsx
import Link from 'next/link'
export default async function Post({ post }) {
const posts = await getPosts()
return (
<ul>
{posts.map(post => (
<li key={post.slug}>
<Link href={`/blog/${post.slug}`}>{post.title}</Link>
</li>
))}
</ul>
)
}
温馨提示:<Link>
是 Next.js 中路由导航的主要方式。您还可以使用 useRouter
钩子进行更高级的导航