{/* Works, since Carousel is a Client Component */}
); }
We don't expect you to need to wrap most third-party components since it's likely you'll be using them within Client Components. However, one exception is provider components, since they rely on React state and context, and are typically needed at the root of an application. Learn more about third-party context providers below.
我们不希望您需要包装大多数第三方组件,因为您很可能会在客户端组件中使用它们。然而,一个例外是提供者组件,因为它们依赖于 React 状态和上下文,并且通常在应用程序的根部需要。在下面了解有关第三方上下文提供程序的更多信息。
Library Authors
以类似的方式,创建供其他开发人员使用的包的库作者可以使用“use client”指令来标记其包的客户端入口点。这允许包的用户将包组件直接导入到他们的服务器组件中,而不必创建包装边界。
You can optimize your package by using 'use client' deeper in the tree, allowing the imported modules to be part of the Server Component module graph.
您可以通过在树的更深处使用“使用客户端”来优化您的包,允许导入的模块成为服务器组件模块图的一部分。
It's worth noting some bundlers might strip out "use client" directives. You can find an example of how to configure esbuild to include the "use client" directive in the React Wrap Balancer and Vercel Analytics repositories.
值得注意的是,一些打包器可能会去掉“使用客户端”指令。你可以在React Wrap Balancer和Vercel Analytics存储库中找到一个如何配置esbuild以包含“use client”指令的示例。
Context
Most React applications rely on context to share data between components, either directly via createContext, or indirectly via provider components imported from third-party libraries.
大多数React应用依赖上下文在组件之间共享数据,要么直接通过createContext,要么间接通过从第三方库导入的提供商组件。
In Next.js 13, context is fully supported within Client Components, but it cannot be created or consumed directly within Server Components. This is because Server Components have no React state (since they're not interactive), and context is primarily used for rerendering interactive components deep in the tree after some React state has been updated.
在 Next.js 13 中,客户端组件完全支持上下文,但不能直接在服务器组件中创建或使用它。这是因为服务器组件没有 React 状态(因为它们不是交互式的),并且上下文主要用于在某些 React 状态更新后重新呈现树深处的交互式组件。
We'll discuss alternatives for sharing data between Server Components, but first, let's take a look at how to use context within Client Components.
我们将讨论在服务器组件之间共享数据的备选方案,但首先让我们看一下如何在客户端组件中使用上下文。
All of the context APIs are fully supported within Client Components:
客户端组件完全支持所有上下文 API:
app/sidebar.tsx 'use client'; import { createContext, useContext, useState } from 'react'; const SidebarContext = createContext(); export function Sidebar() { const [isOpen, setIsOpen] = useState(); return ( ); } function SidebarNav() { let { isOpen } = useContext(SidebarContext); return (
Home
{isOpen && }
); }
However, context providers are typically rendered near the root of an application to share global concerns, like the current theme. Because context is not supported in Server Components, trying to create a context at the root of your application will cause an error:
但是,上下文提供程序通常呈现在应用程序的根附近以共享全局关注点,例如当前主题。由于服务器组件不支持上下文,因此尝试在应用程序的根目录下创建上下文会导致错误:
app/layout.tsx import { createContext } from 'react'; // createContext is not supported in Server Components export const ThemeContext = createContext({}); export default function RootLayout({ children }) { return ( {children} ); }
To fix this, create your context and render its provider inside of a Client Component:
要解决此问题,请创建您的上下文并在客户端组件中呈现其提供者:
app/theme-provider.tsx 'use client'; import { createContext } from 'react'; export const ThemeContext = createContext({}); export default function ThemeProvider({ children }) { return {children} ; }
Your Server Component will now be able to directly render your provider since it's been marked as a Client Component:
您的服务器组件现在可以直接呈现您的提供者,因为它已被标记为客户端组件:
app/layout.tsx import ThemeProvider from './theme-provider'; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( {children} ); }
With the provider rendered at the root, all other Client Components throughout your app will be able to consume this context.
通过在根节点呈现该提供商,应用中的所有其他客户端组件都可以使用该上下文。
Note: You should render providers as deep as possible in the tree – notice how ThemeProvider only wraps {children} instead of the entire document. This makes it easier for Next.js to optimize the static parts of your Server Components.
注意:您应该在树中尽可能深地呈现提供者——注意 ThemeProvider 如何仅包装 {children} 而不是整个 文档。这使 Next.js 更容易优化服务器组件的静态部分。
Rendering third-party context providers in Server Components
Third-party npm packages often include Providers that need to be rendered near the root of your application. If these providers include the "use client" directive, they can be rendered directly inside of your Server Components. However, since Server Components are so new, many third-party providers won't have added the directive yet.
第三方 npm 包通常包含需要在应用程序根目录附近呈现的提供程序。如果这些提供者包含“使用客户端”指令,则它们可以直接在您的服务器组件内呈现。但是,由于服务器组件非常新,许多第三方提供商还没有添加该指令。
If you try to render a third-party provider that doesn't have "use client", it will cause an error:
如果您尝试呈现没有“使用客户端”的第三方提供程序,则会导致错误:
app/layout.tsx import { ThemeProvider } from 'acme-theme'; export default function RootLayout({ children }) { return ( {/* Error: `createContext` can't be used in Server Components */} {children} ); }
To fix this, wrap third-party providers in your own Client Component:
要解决此问题,请将第三方提供商包装在您自己的客户端组件中:
app/providers.js 'use client'; import { ThemeProvider } from 'acme-theme'; import { AuthProvider } from 'acme-auth'; export function Providers({ children }) { return ( {children} ); }
Now, you can import and render directly within your root:
现在,您可以直接在根目录中导入和呈现 :
import { Providers } from './providers'; export default function RootLayout({ children }) { return ( {children} ); }
With the providers rendered at the root, all the components and hooks from these libraries will work as expected within your own Client Components.
通过在根目录中呈现提供程序,这些库中的所有组件和挂钩都将在您自己的客户端组件中按预期工作。
Once a third-party library has added "use client" to its client code, you'll be able to remove the wrapper Client Component.
一旦第三方库将“使用客户端”添加到其客户端代码中,您就可以删除包装客户端组件。
Sharing data between Server Components
在服务器组件之间共享数据
Since Server Components are not interactive and therefore do not read from React state, you don't need the full power of context to share data. You can use native JavaScript patterns like global singletons within module scope if you have common data that multiple Server Component need to access.
由于服务器组件不是交互式的,因此不会从 React 状态读取,因此您不需要上下文的全部功能来共享数据。如果您有多个服务器组件需要访问的公共数据,您可以在模块范围内使用本地 JavaScript 模式,如全局单例。
For example, a module can be used to share a database connection across multiple components:
例如,一个模块可用于跨多个组件共享数据库连接:
utils/database.ts export const db = new DatabaseConnection(...);
app/users/layout.tsx import { db } from "@utils/database"; export async function UsersLayout() { let users = await db.query(...); // ... }
app/users/[id]/page.tsx import { db } from "@utils/database"; export async function DashboardPage() { let user = await db.query(...); // ... }
In the above example, both the layout and page need to make database queries. Each of these components shares access to the database by importing the @utils/database module.
在上面的例子中,布局和页面都需要进行数据库查询。这些组件中的每一个都通过导入 @utils/database 模块来共享对数据库的访问。
Sharing fetch requests between Server Components
在服务器组件之间共享获取请求
When fetching data, you may want to share the result of a fetch between a page or layout and some of its children components. This is an unnecessary coupling between the components and can lead to passing props back and forth between components.
获取数据时,您可能希望在页面或布局与其某些子组件之间共享获取结果。这是组件之间不必要的耦合,可能导致组件之间来回传递 props。
Instead, we recommend colocating data fetching alongside the component that consumes the data. fetch requests are automatically deduped in Server Components, so each route segment can request exactly the data it needs without worrying about duplicate requests. Next.js will read the same value from the fetch cache.
相反,我们建议将数据获取与使用数据的组件放在一起。 fetch 请求在 Server Components 中自动进行重复数据删除,因此每个路由段都可以准确地请求它需要的数据,而不必担心重复请求。 Next.js 将从获取缓存中读取相同的值。