如何使用 Apollo/GraphQL 使派生状态保持最新?

Posted

技术标签:

【中文标题】如何使用 Apollo/GraphQL 使派生状态保持最新?【英文标题】:How to keep derived state up to date with Apollo/GraphQL? 【发布时间】:2020-09-13 17:36:46 【问题描述】:

我的情况是这样的:我的视图中有多个组件最终依赖于相同的数据,但在某些情况下,视图状态是从数据派生的。当基础数据发生变化时,如何确保我的整个视图保持同步?我将使用大家最喜欢的Star Wars API 举例说明。

首先,我显示一个所有电影的列表,查询如下:

# ALL_FILMS
query 
  allFilms 
    id
    title
    releaseDate
  

接下来,我想在 UI 中使用一个单独的组件来突出显示最近的电影。没有查询,所以我将使用客户端解析器来实现它。查询将是:

# MOST_RECENT_FILM
query 
  mostRecentFilm @client 
    id
    title
  

以及解析器:

function mostRecentFilmResolver(parent, variables, context) 
    return context.client.query( query: ALL_FILMS ).then(result => 
        // Omitting the implementation here since it's not relevant
        return deriveMostRecentFilm(result.data);
    )

现在,有趣的是 SWAPI 开始将 The Last JediThe Rise of Skywalker 添加到其电影列表中。我们可以假设我是列表中的polling,以便定期重新获取它。太好了,现在我的列表 UI 是最新的。但是我的“最近的电影”用户界面并没有意识到有什么变化——它仍然停留在 2015 年显示原力觉醒,尽管用户可以清楚地看到有更新的电影。

也许我被宠坏了;我来自MobX 的世界,像 Just Works™ 这样的东西。但这并不像一个不常见的问题。在 Apollo/GraphQL 领域是否有保持同步的最佳实践?我是否以完全错误的方式处理这个问题?

我的一些想法:

我的“最新电影”查询也可以定期轮询。但是您不想经常轮询;毕竟,星球大战电影每隔一年左右才会上映。 (谢谢,迪士尼!)根据轮询间隔的重叠方式,仍然会有一个很大的窗口让事情不同步。 而不是将deriveMostRecentFilm 逻辑放在解析器中,只需将其放在组件中并在组件之间共享ALL_FILMS 查询。那会起作用,但这基本上是在回答“我如何让它在阿波罗工作?”与“不要使用 Apollo”。 一些复杂的系统,用于跟踪查询之间的依赖关系并在此基础上链接刷新。 (如果可以避免的话,我不想发明这个!)

【问题讨论】:

【参考方案1】:

在 Apollo 中,可观察对象(在组件中)超过查询值(缓存数据“槽”),但您的 mostRecentFilm 不是可观察对象,不是基于缓存值(它们被缓存)而是基于一次触发的查询结果(按需更新)。

您只是缺少一个“更新连接”,f.e.像这样:

# ALL_FILMS
query 
  allFilms 
    id
    title
    releaseDate
    isMostRecentFilm @client
  

使用isMostRecentFilm 本地解析器更新缓存中的mostRecentFilm 值。

任何与mostRecentFilm @client 相关的查询 (useQuery) 都会自动更新。所有这些都无需额外的查询、轮询等 - 可以正常工作吗? (未经测试,它应该可以工作);)

【讨论】:

所以要点是:计算原始查询旁边的派生值并将其作为对象保存在缓存中。现在它是缓存中的一个对象,可以观察到它。我相信这会奏效,但感觉很笨拙。现在不是将我的派生逻辑封装在它自己的解析器中,而是泄漏到另一个查询中。这是可行的,但听起来并不是最佳实践。 好吧,不是轮询,而是使用订阅......变化的来源是什么,发出什么消息,一些观察者在记录计数器或插入处理程序上?通常是最后一个(如果只有一个变化源,而不是共享数据库)......这不仅是派生状态,它是一种聚合器(所有记录)......还有什么?基于单项价值的上个月订单价值中位数?两者都应该是后端工作

以上是关于如何使用 Apollo/GraphQL 使派生状态保持最新?的主要内容,如果未能解决你的问题,请参考以下文章

如何访问由点击事件触发的 apollo (GraphQL) 查询的状态

如何在 Apollo / GraphQL 发生突变后更新缓存?

Vuex 状态随突变而变化 - apollo graphql 查询

Redux-Logger 等效于 Apollo / Graphql

当这些变量被删除时,如何停止获取所需导出变量的 Apollo GraphQL 查询

React + Apollo:GraphQL 错误数组未传递到组件中