使用 Apollo 重新获取部分 GraphQL 查询的最佳实践?

Posted

技术标签:

【中文标题】使用 Apollo 重新获取部分 GraphQL 查询的最佳实践?【英文标题】:Best practices for refetching part of a GraphQL query with Apollo? 【发布时间】:2018-06-12 12:52:54 【问题描述】:

我有以下react-apollo-wrapped GraphQL 查询:

user(id: 1) 
  name
  friends 
    id
    name
  

按照语义表示,它获取 ID 为 1 的用户,返回其 name,并返回其所有朋友的 idname

然后,我将其呈现为如下所示的组件结构:

graphql(ParentComponent)
  -> UserInfo
  -> ListOfFriends (with the list of friends passed in)

这一切都对我有用。但是,我希望能够重新获取当前用户的好友列表。

我可以在父组件上做this.props.data.refetch() 并且更新将被传播;但是,我不确定这是不是最佳做法,因为我的 GraphQL 查询看起来更像这样,

user(id: 1) 
  name
  foo1
  foo2
  foo3
  foo4
  foo5
  ...
  friends 
    id
    name
  

虽然我唯一希望重新获取的是朋友列表。

干净地构建这个的最佳方法是什么?我正在考虑将最初跳过的 GraphQL 提取器绑定到 ListOfFriends 组件,这可以在必要时触发,但需要一些关于如何最好地完成此操作的指导。

提前致谢。

【问题讨论】:

我相信 apollo 确实提供了开箱即用的缓存 @mehulmpt 是的,我明白;但是,我不想缓存;我希望重新获取查询的一个小节。 我认为“干净构建这个的最佳方法是什么”这个问题太主观了。你能改写一下,让它不那么主观吗? 【参考方案1】:

我不知道为什么你的问题被否决了,因为我认为这是一个非常有效的问题。 GraphQL 的卖点之一是“一次获取越来越少”。客户端可以从后端非常详细地决定它需要什么。使用以前需要多个端点的深度嵌套的类图查询现在可以在单个查询中表示。同时可以避免过度获取。现在您发现自己有一个大查询,所有内容都立即加载,并且没有 n+1 查询瀑布。但是现在您知道大查询中的一些字段会不时更改,并且您希望使用来自服务器的新数据主动更新缓存。 Apollo 提供了 refetch 字段,但它加载了整个查询,这显然是 overfetching 卖给我的,因为它在 GraphQL 中不再是一个问题。让我提供一些解决方案:

过早的优化?

真正的问题是程序员在错误的地方和错误的时间花费了太多时间来担心效率;过早优化是编程中万恶之源(或至少是大部分)。 - 唐纳德·高德纳

有时我们在没有先测量的情况下尝试优化太多。先把它写得简单,然后看看它是否真的是一个问题。究竟什么是慢?网络?查询中的特定字段?查询的大小?

在您分析了究竟是什么慢之后,我们可以开始考虑改进:

重新获取和包含/跳过指令

使用directives,您可以根据变量从查询中排除字段。 refetch function can specify different variables 比初始查询。这样,您可以在重新获取查询时排除字段。

拆分查询

单页应用是个好主意。 html 是在客户端生成的,页面不必为了呈现新页面而昂贵的访问服务器。但很快 SPA 变得越来越大,代码拆分成了一个问题。现在我们基本上回到了服务器端渲染并将应用程序拆分为页面。这同样适用于 GraphQL。有时查询太大,应该拆分。您可以拆分UserInfoListOfFriends 的查询。在缓存内部,字段将被合并。使用 query batching 时,两个查询将在同一个请求中发送,并且正确实现每个请求资源缓存的 GraphQL 服务器(例如使用 Dataloader)几乎不会注意到差异。

订阅

也许您已经准备好使用订阅。订阅从服务器发送已更改字段的更新。这样您就可以订阅用户的朋友并实时获取更新。好消息是 Apollo 客户端、中继和许多服务器实现已经提供订阅支持。坏消息是,它需要的 websocket 通常对您的技术堆栈提出与纯 HTTP 不同的要求。

withApollo() -> this.client.query

这应该只是你最后的手段!使用react-apollo 的withApollo 高阶组件,您可以直接注入ApolloClient 实例。您现在可以使用this.client.query() 执行查询。 user(id: 1) friendlist ... 可用于获取好友列表并更新缓存,这将导致组件更新。这可能看起来像您想要的,但可能会在应用的后期阶段困扰您。

【讨论】:

太棒了。非常感谢您的深刻见解。

以上是关于使用 Apollo 重新获取部分 GraphQL 查询的最佳实践?的主要内容,如果未能解决你的问题,请参考以下文章

Apollo Graphql:避免在重新获取期间加载指示器

重新获取后 apollo graphql UI 未更新

React Apollo - nodejs graphql后端返回异步响应后如何重新获取(更新)数据

使用 Apollo-Client 重新获取查询会引发错误

删除突变后不重新获取查询(Apollo Graphql & Nextjs)

ReactJS:Apollo graphql 客户端。缓存不在本地更新