在Apollo Client的codegen中如何使用LocalState
这篇文章是 GraphQL Advent Calendar 2020 的第19天文章。
上篇文章是 @policeman-kh 的 GraphQL在Java中的实现。
Apollo Client的本地状态是什么?
公式文件
这是一种机制,可以将本地数据存储在Apollo Client中。在从GraphAPI获取数据的同时,还可以获取本地数据,这是它的优点。此外,它还可以作为替代状态管理库(如Redux)的角色使用。
想做的事
假设已经存在以下这样的数据库。

本次,我们将思考将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”更适合。我打算尝试使用后再写一篇文章。