加入我们,从10月8日至10日在纽约市,了解有关 GraphQL 联邦和 API 平台工程的最新技巧、趋势和新闻。参加2024年纽约市的 GraphQL Summit
文档
免费开始

在 Apollo Client 中重新获取查询


允许您通过数据本地修改。更新缓存,但有时通过从服务器重新获取查询来更新客户端的GraphQL数据会更直接。

理论上,您可以在客户端更新后重新获取每个活动,但实际上,通过更选择性地的重新获取查询,您可以节省时间和网络带宽。InMemoryCache可以帮助您确定哪些活动查询可能在最近的缓存更新中变得无效。

本地缓存更新和重新获取结合使用效果很好:您的应用可以立即显示本地缓存修改的结果,同时在后台重新获取,以获取来自服务器的最新数据。只有当本地数据和重新获取的数据之间有差异时,UI 才会重新渲染。

重新获取在查询后尤其常见,因此mutate 函数接受refetchQueriesonQueryUpdated等选项来指定应重新获取哪些查询以及如何获取。

为了选择性重新获取浆液 外部的突变,您应使用 refetchQueries 方法,该方法属于 ApolloClient,此处有相关文档。

client.refetchQueries

此方法首次出现在 Apollo Client 3.4 中。

重新获取选项

该方法接受一个符合以下 TypeScript 接口的 options 对象,用于指定重新获取浆液的选项:

interface RefetchQueriesOptions<
TCache extends ApolloCache<any>,
TResult = Promise<ApolloQueryResult<any>>,
> {
updateCache?: (cache: TCache) => void;
include?: Array<string | DocumentNode> | "all" | "active";
onQueryUpdated?: (
observableQuery: ObservableQuery<any>,
diff: Cache.DiffResult<any>,
lastDiff: Cache.DiffResult<any> | undefined,
) => boolean | TResult;
optimistic?: boolean;
}

以下列出了这些 的描述:

名称
类型
描述
updateCache

(cache: TCache) => void

可选函数,用于更新缓存的字段并触发包含这些字段的浆液的重新获取。

include

Array<string | DocumentNode> | "all" | "active"

可选数组,指定要重新获取的浆液。每个元素可以是浆液的字符串名称或 DocumentNode 对象。

类似于用于突变的 options.refetchQueries 数组。

使用 "active"(或 "all")作为快捷方式来重新获取所有(活动)浆液。

onQueryUpdated

(observableQuery: ObservableQuery<any>, diff: Cache.DiffResult<any>, lastDiff: Cache.DiffResult<any> | undefined) => boolean | TResult

可选的回调函数,对每个受 options.updateCacheoptions.include(或两者)影响ObservableQuery 进行调用。

如果未提供 onQueryUpdated,则默认实现返回调用 observableQuery.refetch() 的结果。如果提供了 onQueryUpdated,则可以动态决定是否以及如何重新获取每个查询。

onQueryUpdated 返回 false 阻止关联的查询重新获取。

乐观的

布尔值

true 时,options.updateCache 函数会在 InMemoryCache 的临时乐观层上执行,因此其修改可以在观察哪些 fields 它使无效后被从缓存中丢弃。

默认为 false,意味着 options.updateCache 会以持久的方式更新缓存。

重新获取结果

客户端的 refetchQueries 方法收集由 onQueryUpdated 返回的 TResult 结果,默认为 TResult = Promise<ApolloQueryResult<any>> 如果未提供 onQueryUpdated。它使用 Promise.all(results) 将这些结果合并为一个单一的 Promise<TResolved[]>

由于 Promise.allPromise - 解包行为,TResolved 类型通常与 TResult 相同,除非 TResultPromiseLike<TResolved>boolean

返回的 Promise 对象具有另外两个有用的属性:

名称
类型
描述
查询

ObservableQuery[]

一个被重新获取的 ObservableQuery 对象的数组。

结果

TResult[]

一个结果数组,这些结果是通过 onQueryUpdated 返回的,或者在没有 onQueryUpdated 时默认提供的,包括挂起的承诺。

如果 onQueryUpdated 为给定的 query 返回 false,则不为此查询提供任何结果。

如果 onQueryUpdated 返回 true,则结果 Promise<ApolloQueryResult<any>> 会包含在 results 数组中而不是 true

这两个数组相互平行:它们的长度相同,并且 results[i] 是当使用位于 queries[i]ObservableQuery 时,由 onQueryUpdated 产生的结果,对于任何索引 i

重新获取配方

重新获取特定查询

要通过名称重新获取特定的 query,请使用仅包含 include 选项:

await client.refetchQueries({
include: ["SomeQueryName"],
});

选项 include 还可以使用其 DocumentNode 重新获取特定的 query

await client.refetchQueries({
include: [SOME_QUERY],
});

重新获取所有查询

要重新获取所有 活动 查询,请传递 "active"include 简写:

await client.refetchQueries({
include: "active",
});

为了重新获取 所有 由 Apollo 客户端管理的查询(即使是没有观察者或当前未挂载的组件的查询),请将 "all" 传递给 include:

await client.refetchQueries({
include: "all", // Consider using "active" instead!
});

重新获取受缓存更新影响的查询

您可以通过 updateCache 回调来重新获取受缓存更新影响的查询:

await client.refetchQueries({
updateCache(cache) {
cache.evict({ fieldName: "someRootField" });
},
});

这会重新获取任何依赖于 Query.someRootField 的查询,而无需您事先知道哪些查询可能包含在内。允许在 updateCache 中的 writeQuerywriteFragmentmodifyevict 等):

默认情况下,updateCache 在缓存中持久更新。如果您想在 client.refetchQueries Done 观察它们后立即丢弃它们,而不是更改缓存,您可以在临时的乐观层中执行它们:

await client.refetchQueries({
updateCache(cache) {
cache.evict({ fieldName: "someRootField" });
},
// Evict Query.someRootField only temporarily, in an optimistic layer.
optimistic: true,
});

另一种在不实际更改缓存数据的情况下更新缓存的方法是使用 cache.modify 和其 INVALIDATE 信号对象:

await client.refetchQueries({
updateCache(cache) {
cache.modify({
fields: {
someRootField(value, { INVALIDATE }) {
// Update queries that involve Query.someRootField, without actually
// changing its value in the cache.
return INVALIDATE;
},
},
});
},
});

在引入 client.refetchQueries 之前,INVALIDATE 信号无效,因为具有 fetchPolicy: "cache-first" 的无效查询通常会重新读取未更改的结果,因此决定不执行网络请求。client.refetchQueries 方法使此无效化系统更容易为应用程序代码访问,因此您可以控制无效查询的重新获取行为。

在上面的所有示例中,无论我们使用 include 还是 updateCacheclient.refetchQueries 都会从网络上重新获取受影响的查询,并将 Promise<ApolloQueryResult<any>> 结果包括在 Promise<TResolved[]> 返回的 client.refetchQueries

如果特定的 查询 同时被 includeupdateCache 包含,则该查询只会重新获取一次。换句话说,include 选项是一个确保某些查询始终包括在内的好方法,无论哪个查询被 updateCache 包含。

有选择地重新获取

在开发过程中,您可能想要确保适当的查询被重新获取,而不是盲目地重新获取它们。为了在重新获取之前拦截每个 查询,您可以指定一个 onQueryUpdated 回调:

const results = await client.refetchQueries({
updateCache(cache) {
cache.evict({ fieldName: "someRootField" });
},
onQueryUpdated(observableQuery) {
// Logging and/or debugger breakpoints can be useful in development to
// understand what client.refetchQueries is doing.
console.log(`Examining ObservableQuery ${observableQuery.queryName}`);
debugger;
// Proceed with the default refetching behavior, as if onQueryUpdated
// was not provided.
return true;
},
});
results.forEach(result => {
// These results will be ApolloQueryResult<any> objects, after all
// results have been refetched from the network.
});

注意在本例中添加onQueryUpdated并没有改变client.refetchQueries的重新获取行为,这使得我们可以纯粹用于诊断或调试目的。

如果您想跳过某些其他情况下会被包含的查询,请从onQueryUpdated返回false

await client.refetchQueries({
updateCache(cache) {
cache.evict({ fieldName: "someRootField" });
},
onQueryUpdated(observableQuery, { complete, result, missing }) {
console.log(`Examining ObservableQuery ${
observableQuery.queryName
} whose latest result is ${JSON.stringify(result)} which is ${
complete ? "complete" : "incomplete"
}`);
if (shouldIgnoreQuery(observableQuery)) {
return false;
}
// Refetch the query unconditionally from the network.
return true;
},
});

如果ObservableQuery提供的信息不足,您也可以检查查询的最新result,以及有关其complete性和缺失字段的DiffResult对象,该对象作为onQueryUpdated的第二个参数传入:

await client.refetchQueries({
updateCache(cache) {
cache.evict({ fieldName: "someRootField" });
},
onQueryUpdated(observableQuery, { complete, result, missing }) {
if (shouldIgnoreQuery(observableQuery)) {
return false;
}
if (complete) {
// Update the query according to its chosen FetchPolicy, rather than
// refetching it unconditionally from the network.
return observableQuery.reobserve();
}
// Refetch the query unconditionally from the network.
return true;
},
});

由于onQueryUpdated具有动态过滤查询的能力,因此它与上面提到的批量include选项也很好地配合使用:

await client.refetchQueries({
// Include all active queries by default, which may be ill-advised unless
// you also use onQueryUpdated to filter those queries.
include: "active";
// Called once for every active query, allowing dynamic filtering:
onQueryUpdated(observableQuery) {
return !shouldIngoreQuery(observableQuery);
},
});

处理重取错误

在上面的例子中,我们使用await client.refetchQueries(...)来获取所有重取查询的最终ApolloQueryResult<any>结果。这个合并的Promise.all被创建,所以一个失败会拒绝整个Promise<TResolved[]>,可能隐藏其他成功的结果。如果这是一个问题,您可以使用client.refetchQueries返回的queriesresults数组来代替(或与)await

const { queries, results } = client.refetchQueries({
// Specific client.refetchQueries options are not relevant to this example.
});
const finalResults = await Promise.all(
results.map((result, i) => {
return Promise.resolve(result).catch(error => {
console.error(`Error refetching query ${queries[i].queryName}: ${error}`);
return null; // Silence this Promise rejection.
});
})
});

在未来,正像可能会向client.refetchQueries方法添加额外的输入选项一样,它的结果对象可能会添加更多属性,补充其Promise相关属性以及queriesresults数组。

如果您发现某些特定的额外client.refetchQueries输入选项或结果属性可能会有所帮助,请随时在这里打开一个问题

对应的 client.mutate 选项

client.mutate支持与选项类似,您应该使用它而不是client.refetchQueries,因为重取逻辑在mutation的过程中的特定时间点是重要的。

由于历史原因, client.mutate 选项的名称与新的 client.refetchQueries 选项略有不同,但它们的内部实现基本上相同,因此您可以使用以下表格在它们之间进行转换:

client.mutate(options)client.refetchQueries(options)
options.refetchQueriesoptions.include
options.updateoptions.updateCache
options.onQueryUpdatedoptions.onQueryUpdated
options.awaitRefetchQueriesonQueryUpdated 返回一个 Promise
上一页
变体
下一页
订阅
评价文章评价在 GitHub 上编辑编辑论坛Discord

©2024Apollo Graph Inc.,商业名称:Apollo GraphQL。

隐私政策

公司