在Apollo Client的codegen中如何使用LocalState

这篇文章是 GraphQL Advent Calendar 2020 的第19天文章。
上篇文章是 @policeman-kh 的 GraphQL在Java中的实现。

Apollo Client的本地状态是什么?

公式文件

这是一种机制,可以将本地数据存储在Apollo Client中。在从GraphAPI获取数据的同时,还可以获取本地数据,这是它的优点。此外,它还可以作为替代状态管理库(如Redux)的角色使用。

想做的事

假设已经存在以下这样的数据库。

image.png

本次,我们将思考将users.id保存为activeUserId在本地状态(Local State)中的方法。

本次使用的环境

    • React

 

    • Apollo Client

 

    • GraphQL Code Generator

 

    hasura

假设查询(query)和变更(mutation)已经正常工作,并且我们希望添加本地状态(Local State)。

補充說明:Hasura是什麼?

这是一个可以自动构建PostgreSQL到GraphQL API服务器的工具。它使得可以对存储在Postgre数据库中的数据进行GraphQL查询。

代码生成器的配置

在使用Local State时,需要在客户端模式中手动添加一些在GraphQL服务器模式中不存在的字段和列。因此,首先需要将schema的路径添加到codegen配置文件中,以便让codegen能够识别客户端模式的schema。

module.exports = {
  schema: [
      "http://localhost:8080/v1/graphql",
      "src/graphql/local-schema.graphql", //追加
  ],

客户端的模式编写方式

可以通过在客户端模式中写入以下内容来将activeUserId字段添加到查询中。

extend type Query {
  activeUserId: Int!
}

您可以按照以下方式使用它。

query MyArticles($id: Int!) {
  activeUserId @client @export(as: "id")
  user: users_by_pk(id: $id) {
    id
    name
    articles {
      id
      body
    }
  }
}

对于@client部分,意思是“使用缓存的activeUserId”。

通过@export(as: “id”),可以将activeUserId作为$id传递给users_by_pk的参数。

当使用useQuery的时候,就不需要额外传递activeUserId了。

const { data } = useMyArticlesQuery();

另外,

console.log(data?.activeUserId);

也可以获取以缓存方式存储的activeUserId。

※使用Hasura时的注意事项

在 Hasura 中,使用上述的 local-schema.graphql 的写法会出现错误。

 AggregateError: 
        GraphQLDocumentError: Cannot query field "activeUserId" on type "quer
y_root".

通过写成以下方式,解决了 extend type Query 的问题。

type query_root {
  activeUserId: Int!
}

操作Local State的值

使用client.writeQuery。

    await client.writeQuery({
      query: MyArticlesDocument,
      data: { activeUserId: 1 },
    });

通过这样做,可以将MyArticles查询中的acitveUserId更改为1。

在这个翻译任务中,只需要提供一个选项:
作为注意事项,在这次的情况下,

    • query単位でのキャッシュ

 

    フィールド単位でのキャッシュ

如果同时更新了这两个,那么如果在其他查询中使用了activeUserId,那么该缓存也会自动更新。

请务必参考GraphQL Advent Calendar 2020第2天,其中详细介绍了关于缓存的内容。

补充完善

以前有一个名为 `client.writeData`(或 `cache.writeData`)的方法。然而,根据官方说明,它在 v3.0 版本中已被废弃。

已完全移除client|cache.writeData。可以使用client|cache.writeQuery、client|cache.writeFragment和/或cache.modify来更新缓存。

根据公关消息,据说调用cache.writeData会重新执行所有查询,这是非常低效的。

总结

据说为了使用Apollo而不使用Redux等,引入了Local State,以实现对远程数据和本地数据的统一管理。
(参考:https://www.apollographql.com/blog/the-future-of-state-management-dd410864cae2/)

从历史上看,Apollo用户将那20%数据管理在一个独立的Redux或MobX存储中。这在Apollo Client 1.0中是可行的解决方案,但当Apollo Client 2.0不再依赖Redux时,同步本地和远程数据成为一个更麻烦的问题。我们经常听到用户希望将其应用程序的所有状态封装在Apollo Client中,并保持一个真实的状态来源。

这次我尝试使用”将activeUserId放入LocalState以便更轻松地使用查询”来实现目的,但如果只是想进行状态管理,好像Apollo Client v3.0的新功能”reactive variables”更适合。我打算尝试使用后再写一篇文章。

bannerAds