Apollo 客户端支持 Next.js App路由器
| 阿波罗客户端用户调查 |
|---|
| 你喜欢阿波罗客户端吗? 需要改进的是什么? 请告诉我们,拿一个 一分钟调查您的答复将帮助我们了解阿波罗客户的使用情况,并让我们更好地服务您. |
阿波罗客户端技能
给予你的AI特工阿波罗专业客户端知识和设置指导:
npx skills add apollographql/skills --skill apollo-client
技术细目
您可以从技术上详细了解该软件包的用途和为何需要这样做 在讨论配套的RFC时。 。 。 .
你为什么需要这个?
反应服务器组件
如果您想在 Aproolo 客户端的 Next.js 应用程序中使用 React 服务器组件, 您需要一种方法来创建客户端实例, 该实例由您的服务器组件共享, 以防止重复请求 .
反应客户端组件
使用时 app 目录,您的"客户端组件"将不仅运行在浏览器中. 它们也会在服务器上被渲染出 - 在 React Server 组件被渲染后执行的" SSR" 运行中.
如果您想要充分利用您的应用程序, 您可能已经想要在服务器上实现您的 GraphQL 请求, 以便页面在到达浏览器时完全解析 .
此软件包提供了在服务器上执行您的 GraphQL 查询以及使用结果将您的浏览器侧缓存和组件水化所需的工具 .
安装
此软件包对端依赖最近 @apollo/client,因此可以同时安装此软件包和阿波罗客户端版本
npm install @apollo/client@latest @apollo/client-integration-nextjs
使用量
❗️ 我们处理"RSC"和"SSR"是完全分开的.
通常你应该尽量避免两者之间的查询重叠,因为SSR中所做的所有查询都可以在浏览器中作为缓存更新(例如从一个突变或另一个查询)进行动态更新,但是在RSC中所做的查询将不会在浏览器中更新-为此,整个页面需要重新回复. 因此,任何数据相重叠会导致你的UI不一致.
由你自己决定,你想在RSC和SSSR中 问哪些问题,不要有重叠.
在RSC语中
创建一个 ApolloClient.js 文件 :
import { HttpLink } from "@apollo/client";
import {
registerApolloClient,
ApolloClient,
InMemoryCache,
} from "@apollo/client-integration-nextjs";
export const { getClient, query, PreloadQuery } = registerApolloClient(() => {
return new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({
// this needs to be an absolute url, as relative urls cannot be used in SSR
uri: "http://example.com/api/graphql",
fetchOptions: {
// you can pass additional options that should be passed to `fetch` here,
// e.g. Next.js-related `fetch` options regarding caching and revalidation
// see https://nextjs.org/docs/app/api-reference/functions/fetch#fetchurl-options
},
}),
});
});
那你可以用这个 getClient 函数在服务器组件中:
const { data } = await getClient().query({ query: userQuery });
// `query` is a shortcut for `getClient().query`
const { data } = await query({ query: userQuery });
如果您想要覆盖 Next.js 特定 fetch 选项,您可以使用 context.fetchOptions数字 :
const { data } = await getClient().query({
query: userQuery,
context: {
fetchOptions: {
// you can pass additional options that should be passed to `fetch` here,
// e.g. Next.js-related `fetch` options regarding caching and revalidation
// see https://nextjs.org/docs/app/api-reference/functions/fetch#fetchurl-options
},
},
});
说明 PreloadQuery,参见 在 RSC 中预装数据供客户端组件使用
在客户端组件和流媒体系统
如果你使用 app 目录,每个客户端组件 将 将在初始请求中提交安全部门改革。 所以你需要使用这个包.
首先创建一个新文件 app/ApolloWrapper.jsx数字 :
"use client";
// ^ this file needs the "use client" pragma
import { HttpLink } from "@apollo/client";
import {
ApolloNextAppProvider,
ApolloClient,
InMemoryCache,
} from "@apollo/client-integration-nextjs";
// have a function to create a client for you
function makeClient() {
const httpLink = new HttpLink({
// this needs to be an absolute url, as relative urls cannot be used in SSR
uri: "https://example.com/api/graphql",
// you can disable result caching here if you want to
// (this does not work if you are rendering your page with `export const dynamic = "force-static"`)
fetchOptions: {
// you can pass additional options that should be passed to `fetch` here,
// e.g. Next.js-related `fetch` options regarding caching and revalidation
// see https://nextjs.org/docs/app/api-reference/functions/fetch#fetchurl-options
},
// you can override the default `fetchOptions` on a per query basis
// via the `context` property on the options passed as a second argument
// to an Apollo Client data fetching hook, e.g.:
// const { data } = useSuspenseQuery(MY_QUERY, { context: { fetchOptions: { ... }}});
});
// use the `ApolloClient` from "@apollo/client-integration-nextjs"
return new ApolloClient({
// use the `InMemoryCache` from "@apollo/client-integration-nextjs"
cache: new InMemoryCache(),
link: httpLink,
});
}
// you need to create a component to wrap your app in
export function ApolloWrapper({ children }: React.PropsWithChildren) {
return (
<ApolloNextAppProvider makeClient={makeClient}>
{children}
</ApolloNextAppProvider>
);
}
现在你可以包起来 RootLayout 填充器组件中:
import { ApolloWrapper } from "./ApolloWrapper";
// ...
export default function RootLayout({
children,
}: {
children: React.ReactNode,
}) {
return (
<html lang="en">
<body>
<ApolloWrapper>{children}</ApolloWrapper>
</body>
</html>
);
}
QQ 即使您的版式是 React Server 组件, 也可以让版式的子程序是 React Server 组件 .
它只是确保所有客户端组件都能够访问相同的阿波罗客户端实例,通过ApolloNextAppProvider。 。 。 .
如果您想要充分利用 React & the Next.js App Router 提供的流媒体 SSR 特性,请考虑使用 useSuspenseQuery 财务报告和审定财务报表 useFragment 钩子.
在 RSC 中预装数据供客户端组件使用
从0.11版本开始,您可以在RSC中预装数据来充入客户端组件的缓存.
为此,遵循最后两段所述的RSC和客户部分的设置步骤。 那你可以用这个 PreloadQuery 在您的 React 服务器组件中的组件 :
<PreloadQuery
query={QUERY}
variables={{
foo: 1,
}}
>
<Suspense fallback={<>loading</>}>
<ClientChild />
</Suspense>
</PreloadQuery>
{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你还可以用 useSuspenseQuery 在你身边 ClientChild 具有相同QUERY和变量的组件:
"use client";
import { useSuspenseQuery } from "@apollo/client";
// ...
export function ClientChild() {
const { data } = useSuspenseQuery(QUERY, { variables: { foo: 1 } });
return <div>...</div>;
}
[TIP] 这个
Suspense这里的边界是可选的,并且只是为了展示一些令人悬念的事情正在发生.
地点Suspense在您的用户界面中有意义的地方设置边框,让用户获得最好的用户体验.
此示例将在 RSC 中获取查询, 然后将数据传送到客户端组件缓存 .
在孩子出生之前 ClientChild 在示例中,此查询的“模拟网络请求”将在您的客户端组件中启动.
这样的话, 如果您在客户端组件中重复查询 useSuspenseQuery (或甚至 useQuery!),它将等待您服务器组件中的网络请求完成,而不是让它成为自己的网络请求.
[大 记住,我们不建议在客户端组件和服务器组件之间混合数据. 以这种方式获取的数据应被视为客户端数据, 并且从不在您的服务器组件中引用 .
PreloadQuery通过创建单独的服务器数据和客户端数据防止混合ApolloClient实例makeClient函数转换为registerApolloClient。 。 。 .
[TIP] 使用时
@defer数字 :<PreloadQuery>允许将您的被推迟的数据以整块和整块的方式流出, 而没有任何截断, 就像您会在浏览器中进行同样的查询 .
用法为 useReadQuery
就像使用 useBackgroundQuery 与 useReadQuery 替换 useSuspenseQuery 避免请求瀑布,也可以使用 PreloadQuery 结合 useReadQuery 在客户端组件中实现类似结果。 使用渲染标记来获取 QueryRef 可以传递给客户端组件 :
<PreloadQuery
query={QUERY}
variables={{
foo: 1,
}}
>
{(queryRef) => (
<Suspense fallback={<>loading</>}>
<ClientChild queryRef={queryRef} />
</Suspense>
)}
</PreloadQuery>
内部 ClientChild你可以打电话 useReadQuery 与 queryRef 道具 (英语).
"use client";
import { useQueryRefHandlers, useReadQuery, QueryRef } from "@apollo/client";
export function ClientChild({ queryRef }: { queryRef: QueryRef<TQueryData> }) {
const { refetch } = useQueryRefHandlers(queryRef);
const { data } = useReadQuery(queryRef);
return <div>...</div>;
}
[TIP] 这个
Suspense这里的边界是可选的,并且只是为了展示一些令人悬念的事情正在发生.
地点Suspense在您的用户界面中有意义的地方设置边框,让用户获得最好的用户体验.
卡维特
记住,这对您的客户端组件来说将看起来像是“当前网络请求”,因此将更新客户端组件缓存中已经存在的数据,从而确保您从服务器组件传递的数据不会过时,例如,由于您可能正在使用的其他缓存层,比如Next.js获取缓存.
在测试之间重设置单吨数
此软件包在浏览器侧面使用一些单通实例 - 如果您正在写入测试, 您必须在测试之间重置它们 .
为此,你可以使用 resetApolloClientSingletons 帮助者 :
import { resetApolloClientSingletons } from "@apollo/client-integration-nextjs";
afterEach(resetApolloClientSingletons);
处理安全部门改革中的多部门反应
一般来说, useSuspenseQuery 只会暂停,直到收到初步答复.
在大多数情况下,你得到一个完整的响应,但如果使用多段响应功能,比如: @defer 指令,你只能得到部分响应.
如果不进行进一步处理, 您的组件现在将会用部分数据渲染 - 但是请求仍然会持续在背景中运行 。 这是一个最坏的情况,因为您的服务器将不得不承担该请求的负载,但客户端无论如何都无法获得完整的数据.
要处理这个问题,您可以应用三种不同的策略之一:
- 使用情况
PreloadQuery与useReadyQuery- 说吧PreloadQuery将允许@defer要完全传送的红色数据 - 删除
@defer从您的查询中找到的片段 。 这将允许您在 SSR 中预发一些信息, 但查询会再次在浏览器中重新启动 . - 等待收到延迟数据,或者使用
AccumulateMultipartResponsesLink或者说useSuspenseFragment特别是等待被推迟的碎片.
为了这个,我们把两个环节都运走 RemoveMultipartDirectivesLink 财务报告和审定财务报表 AccumulateMultipartResponsesLink,以及 SSRMultipartLink,将两者结合为更方便使用的链接.
也可以检查 Hack 超级图例,它显示在使用中,并允许您调整速度延后接口的解析.
删除 @defer 您查询中的片段 RemoveMultipartDirectivesLink
用法示例:
new RemoveMultipartDirectivesLink({
/**
* Whether to strip fragments with `@defer` directives
* from queries before sending them to the server.
*
* Defaults to `true`.
*
* Can be overwritten by adding a label starting
* with either `"SsrDontStrip"` or `"SsrStrip"` to the
* directive.
*/
stripDefer: true,
});
此链接将( 如果调用 stripDefer: true脱去所有 @defer 从您的查询中找到的片段 .
您可以从此行为中排除某些片段, 给它们一个标签 "SsrDontStrip"。 。 。 .
示例
query myQuery {
fastField
... @defer(label: "SsrDontStrip1") {
slowField1
}
... @defer(label: "SsrDontStrip2") {
slowField2
}
}
您也可以使用链接 stripDefer: false 并标记某些要剥取的碎片,从标签开始 "SsrStrip"。 。 。 .
等待收到延迟数据 AccumulateMultipartResponsesLink
用法示例:
new AccumulateMultipartResponsesLink({
/**
* The maximum delay in milliseconds
* from receiving the first response
* until the accumulated data will be flushed
* and the connection will be closed.
*/
cutoffDelay: 100,
});
此链接可用于"解除"多部分请求的初始响应. (b) 任何增量数据 cutoffDelay 时间将合并为初始响应.
之后 cutoffDelay,链接将返回初始响应,即使仍然有增量数据等待,并关闭网络连接.
若为 cutoffDelay 实值 0,链接将在收到数据后立即返回数据,而不等待增量数据,并立即关闭网络连接.
两者结合: SSRMultipartLink
用法示例:
new SSRMultipartLink({
/**
* Whether to strip fragments with `@defer` directives
* from queries before sending them to the server.
*
* Defaults to `true`.
*
* Can be overwritten by adding a label starting
* with either `"SsrDontStrip"` or `"SsrStrip"` to the
* directive.
*/
stripDefer: true,
/**
* The maximum delay in milliseconds
* from receiving the first response
* until the accumulated data will be flushed
* and the connection will be closed.
*
* Defaults to `0`.
*/
cutoffDelay: 100,
});
此链接结合了 RemoveMultipartDirectivesLink 财务报告和审定财务报表 AccumulateMultipartResponsesLink 进入单一链接.
调试
如果您想要更多关于通过电线发送的数据的信息, 请启用您的日志 app/ApolloWrapper.ts数字 :
import { setLogVerbosity } from "@apollo/client";
setLogVerbosity("debug");