Next.js 常见问题解答
Web 开发从服务器渲染应用发展到完全在客户端渲染的单页应用,一切都变得复杂起来。Next.js 现在已经打破了客户端和服务器的旧有视角,为我们提供了一个高性能框架,它是一个包含客户端和服务器的大黑盒子。不过别担心,我会在这里提供一个常见问题解答,解答关于 Next.js 及其服务器组件的常见问题。
在本文中
- 如何在客户端组件中读取 URL 参数?
- 如何读取页面文件中的 URL 参数?
- 如何在 Next.js 布局文件中读取 URL 参数?
- 如何在服务器组件中读取 URL 参数?
- 为什么 Next.js 布局文件中不存在 searchParams?
- 如何在 Next.js 中跳过某些页面的根布局?
- 如何在 App Router 中设置元数据标签?
- 如何为应用路由器页面动态设置元数据?
- 我可以在布局文件中设置元数据吗?
- 我可以将上下文与 App Router 一起使用吗?
- 如何在服务器组件中使用 React Context?
- 是否可以在服务器组件中呈现客户端组件?
- 我可以将 Props 从服务器组件传递到客户端组件吗?
- 我可以在客户端组件中使用服务器组件吗?
- 我可以将 Props 从客户端组件传递到服务器组件吗?
- 我可以在服务器组件中使用服务器操作吗?
- 我可以在客户端组件中使用服务器操作吗?
- Next.js 中的服务器操作是否稳定?
1.如何在客户端组件中读取URL参数?
如果您需要从客户端组件中的 URL 读取路径名或查询参数,则可以使用usePathname或useSearchParams来执行此操作。
'use client'
import { usePathname, useSearchParams } from 'next/navigation'
const ClientComponent({ children, href }) {
const pathname = usePathname()
const searchParams = useSearchParams()
const search = searchParams.get('search')
return (
<div>Next.js usePathname and useSearchParams example</div>
<div>{pathname}</div>
<div>{search}</div>
)
}
export default ClientComponent
如果您需要在客户端组件中以编程方式导航,可以使用useRouter。对于常规导航,请使用 Next.js 内置的 Link 组件。
'use client'
import { useRouter } from 'next/navigation'
const ClientComponent({ children }) {
const router = useRouter()
const handleClick = () => {
router.push('someUrl')
}
return (
<div onClick={handleClick}>Click me</div>
)
}
export default ClientComponent
2.如何读取页面文件中的URL参数?
参数会自动作为 props 传递给页面组件。您可以直接使用提供的 props。
const PageComponent({ params, searchParams }) {
const { slug } = params
return <div>Next.js URL params in page.tsx file</div>
}
export default PageComponent
3. 如何读取 Next.js 布局文件中的 URL 参数?
如果您需要读取布局组件文件中的 URL 参数,则有两种选择。第一种是在布局中创建一个客户端组件,并在该组件中读取参数。
如果你使用 Next.js 并期望主要使用服务器组件,这听起来可能不太好,但实际上这是完全自然的。你的布局文件的其余部分仍然可以作为服务器组件渲染,只是客户端组件本身需要在客户端渲染。
例如,如果您使用 URL 参数在芯片组件的帮助下过滤博客文章,那么只有包含芯片的组件才需要是客户端组件,其余标题可以保留为服务器组件。
在上面的网站中,红色矩形可以作为服务器组件,而依赖于 URL 参数的蓝色矩形可以作为客户端组件
另一个方案可能不太理想。那就是在你的应用程序中添加一个中间件,它读取 URL 参数并将其传递给你的布局组件。这将使你能够灵活地访问 URL 参数,但代价是禁用服务器组件的静态渲染和客户端缓存。
4.如何在服务器组件中读取URL参数?
在任意服务器组件中(既不是布局组件也不是页面组件),您可以通过将 URL 参数作为 props 从其他组件传递下来来获取它们。
需要注意的是,非页面文件组件的服务器组件通常不会在导航过程中刷新,这些组件会整体序列化并发送到客户端,并且仅在极少数情况下才会更新。因此,在服务器组件中使用 URL 中的信息时必须谨慎。URL 参数在导航时可能会过期。
5. 为什么 Next.js 布局文件中不存在 searchParams?
searchParams 仅在页面文件中可用是有原因的。在两个页面之间导航时,页面文件总是会重新渲染。由于组件会在 URL 更改时重新渲染,因此我们可以确定传递给组件的 URL 参数是最新的。
布局组件的目的是避免不必要的渲染,并包含 UI 中在用户页面间导航时不会更新的静态部分。因此,布局组件仅当用户导航到屏幕上该组件不可见的另一部分时才会重新渲染。在代码中,这意味着在文件树中不共享公共布局文件作为祖先的两个页面之间导航。
实际上,这意味着 URL 的更改频率比布局文件渲染的频率要高,如果我们在布局组件中读取 URL 参数,组件将无法知道 URL 参数何时更新。请记住,布局文件是一个服务器组件,它在首次获取时会渲染为 HTML,然后缓存在客户端,因此无需重新渲染。
要了解更多信息,请阅读上面关于如何在 Next.js 布局文件中读取 URL 参数的部分。
6. 如何在 Next.js 中跳过某些页面的根布局?
Next.js 项目可以包含多个布局文件,严格来说,每个页面都可以有自己的布局文件。封装整个应用程序的顶层布局文件称为根布局文件。
布局文件允许您将一个组件重复用作多个页面的包装组件。最常见的情况是,每个 Next.js 应用程序都有一个根布局文件,其中包含应用程序的主菜单,例如标题菜单或英雄图像。
在执行此操作时,您很快就会遇到一个问题:您可以跳过特定页面的根布局吗?答案是可以的。Next.js 有一个名为“路由组”的功能,允许您拥有多个根布局。这意味着应用程序的不同部分可以拥有不同的布局,这也使得在某些页面的布局中完全跳过任何组件成为可能。
这里需要注意的是,路由组之间的导航会触发整个页面的加载。这是替换应用程序中顶级服务器组件的自然结果。这基本上意味着,你将渲染应用程序的一个全新部分,该部分独立于所有页面的其余部分。
7.如何在App Router中设置元数据标签?
Next.js 让您可以非常轻松地为应用和页面设置元数据。您只需从应用程序中的任何布局或页面文件导出元数据对象,即可设置该布局/页面及后续内容的元数据。
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Next.js Metadata Example',
description: 'Example of metadata in Next.js',
}
export default function MyPage() { ... }
如果您需要动态数据,请参阅下面的问题。
8.如何为应用路由器页面动态设置元数据?
对于大多数 SEO 优化的应用程序来说,设置静态元数据是不够的,因为数据几乎对每个页面都是唯一的,甚至会在运行时从服务器加载。要在 Next.js 页面中动态设置元数据,请使用提供的 generateMetadata 函数。
import type { Metadata } from 'next'
export async function generateMetadata(): Promise<Metadata> {
const data = await fetch('someUrl').then((res) => res.json())
return {
title: 'Next.js Dynamic Metadata Example',
description: data.pageDescription,
}
}
export default function MyPage() { ... }
需要注意的是,Next.js 中的 fetch 函数默认会缓存重复的请求。这是一种普遍现象,并非特定于元数据。使用 fetch 时,即使是服务器组件中的请求也会被缓存。不过,在使用某些 Next.js 功能时,您可以选择退出,甚至自动禁用此功能。
9. 我可以在布局文件中设置元数据吗?
是的,您可以在布局文件中设置元数据,无论是静态的还是动态的。请参阅上面关于设置元数据的问题。
10. 我可以将上下文与 App Router 一起使用吗?
在 Next.js 中,可以将 React 上下文与 App Router 一起使用。最好将上下文放置在根布局中,以便所有客户端组件都可以使用。该上下文将无法在服务器组件中使用,并且不会干扰服务器组件的渲染行为。
您可以在本文中了解其工作原理。
11.如何在服务器组件中使用 React Context?
在 Next.js 中,你只能在客户端组件中使用 React 上下文。服务器组件不会受到客户端组件中上下文的影响,也无法读取上下文。有关更多信息,请参阅“ Next.js 13 中的上下文是否会影响整个应用在客户端渲染? ”。
但是,根据您的需要,服务器组件中可能不需要上下文。默认情况下,Next.js 会缓存使用 fetch 函数发送的请求中检索的数据,这意味着您不必担心重复请求。如果多个服务器组件需要获取相同的数据,您可以依赖缓存作为通过上下文共享数据的替代方案。
12. 是否可以在服务器组件中渲染客户端组件?
在服务器组件中渲染客户端组件是完全正常的。所有传递给客户端组件的 props 都必须是可序列化的。不可序列化的数据必须在客户端组件内部处理。
13. 我可以将 Props 从服务器组件传递到客户端组件吗?
是的,可以将 props 从服务器组件传递到客户端组件。如上一个问题所述,数据必须是可序列化的。
14.我可以在客户端组件中使用服务器组件吗?
可以在客户端组件中使用服务器组件,但有一些限制。您无法像往常一样在客户端组件中导入服务器组件,因为导入后它们将不再是服务器组件。您需要做的是将服务器组件作为 prop 或 child 传递给客户端组件。
特别需要注意的是,这会让很多开发者感到困惑。Next.js 声称组件默认是服务器组件,你必须使用“use client”指令才能使其成为客户端组件。但这并非全部事实,因为当你在客户端组件中导入任何组件时,导入的组件将是客户端组件,而不是服务器组件。
如上所述,如果要将服务器组件视为服务器组件,则必须将其作为 prop 传递。如果您将您认为是服务器组件的内容导入到客户端组件中,Next.js 不会报错,它们会直接被视为客户端组件,而不会发出任何警告。因此,如果您认为自己使用了很多服务器组件,那么实际上可能根本没有那么多。
15. 我可以将 Props 从客户端组件传递到服务器组件吗?
不可以,无法将 props 从客户端组件传递到服务器组件。服务器组件在客户端组件渲染之前就已经在服务器上渲染成 HTML 了。
16.我可以在服务器组件中使用服务器操作吗?
是的,当然,它们就是为此而设计的。请参阅文档中的这个示例。
17.我可以在客户端组件中使用服务器操作吗?
是的,但有一个警告。您不能在客户端组件中直接使用服务器操作。您可以做的是,将服务器操作编写在单独的文件中,然后在客户端组件中使用它,就像文档中所示的那样。
但是,如果您尝试在组件中直接使用服务器操作(就像在服务器组件中一样),那么您会收到此错误。
不允许在客户端组件中定义内联“使用服务器”注释的服务器操作。│ 要在客户端组件中使用服务器操作,您可以从顶部带有“使用服务器”的单独文件中导出它们,也可以通过服务器组件中的 props 将它们传递下去。
正如您所读到的,您还有一个选择。您可以在服务器组件中定义服务器操作,并将其作为 prop 传递给客户端组件(如果您愿意)。
18. Next.js 中的服务器操作是否稳定?
在 Next.js 中,14 个服务器操作被认为是稳定的。但需要注意的是,Next.js 是基于 React 功能构建的,而这些功能仍被标记为“实验性”。
服务器操作在 Next.js 13 中处于实验阶段,因此如果在版本 13 中,您将被要求在 next.config.js 中添加服务器操作作为实验功能
要使用服务器操作,请在 next.js 配置中启用功能标志。
这些是您需要添加到 next.config.js 的内容。不过我更建议升级到 Next.js 14。
experimental: {
serverActions: true,
},