资讯专栏INFORMATION COLUMN

21 分钟学 apollo-client 系列:apollo store 存储细节

lavor / 1042人阅读

摘要:分钟学是一个系列,简单暴力,包学包会。内部通过自己的私有没有暴露给开发者来更新这个。相当于这个就是自己维护的,它将所有通过得到的数据保存在这里。的生成规则根据官方文档的说法,在创建时,可选设置。如果不存在,则可能出现。

21 分钟学 apollo-client 是一个系列,简单暴力,包学包会。

搭建 Apollo client 端,集成 redux
使用 apollo-client 来获取数据
修改本地的 apollo store 数据
提供定制方案

请求拦截

封装修改 client 的 api
apollo store 存储细节

写入 store 的失败原因分析和解决方案

Apollo 集成 Redux 的原理

Apollo 仅仅是在 Redux 下开辟了一个 reducer,比如就叫 apollo。apollo 内部通过自己的私有 action (没有暴露给开发者)来更新这个 reducer 。
相当于这个 reducer 就是 Apollo 自己维护的 store ,它将所有通过 GraphQL query 得到的数据保存在这里。

我们只能通过以下几种办法来修改 apollo store

query 成功后,通过 updateQuery 回调修改 store

几个有限的命令式接口

Mutation

第二种方式,虽然接口是命令式的,但并不是直接修改 state 的值,背后本质是在调用它内部私有的 action ,最终还是以 dispatch 的形式修改 store。只是这个过程对开发者是屏蔽的。
当然你必须提供对应的 GraphQL Schema (一段用 gql 语法描述的 query 或 fragment),最终的数据结构如果不符合 Schema ,会 静默 失败。
更具体的解释和运用,看 修改本地的 apollo store 数据 一节。

Apollo 的数据存储

可能你会问,既然 Apollo 的 store 是存在 redux 的 store 中的,自己写 reducer 去改不就好了吗?
这很容易想到,但不容易实现。

我们看看 apollo store 中数据存储的结构:

很像 normalizr 对不对?

简单说,apollo store 中存储的是扁平化的缓存。

当你想要直接修改 reducer 数据时,你需要

手动计算出对应想去修改的 reducer 的 key

当需要处理一个多层嵌套的实体时,还需要根据其嵌套的其它 __typename 找出其它嵌套的 reducer。这个过程也是递归的。

所以,手动写 reducer 去更新 apollo store 会相当麻烦。

扁平化数据

展开来说的话,Apollo 和 normalizr 之类的数据扁平化方案一样,只是一切都被自动化了,省去了你用 normalizr 手写的体力活,算是为数不多的惊喜了。

如果你没有接触过 normalizr ,那硬要用 reducer 的术语来描述的话,我们可以把 apollo 这个 reducer 视为一个 store。
在这个 store 中, 每一个存入 store 的实体都以 __typename:id 的方式多带带存放到一个 reducer 中,__typename 取自于你请求时使用的 GraphQL Schema,如 UserTimeline:260
如果你从后端接收到一组 UserTimeline ,那么其中每一项都会在 store 里注册一个 reducer ,可能会出现 UserTimeline:1 ~ UserTimeline:100 的盛景。当你在别的请求中再请求到 UserTimeline:260 的时候,就直接 merge 到原有的 reducer 中。

你可能说这样很好啊,直接根据这个 key 访问对应的 state 就可以了。但问题是,凡是嵌套结构,都会被抽出来多带带作为一个 reducer。
比方说,上图中 UserTimeline 包含一个 userInfo, 它的 __typenameUserInfo,那么 UserTimeline:260 下的 userInfo 中存储只是对应的 reducer 索引,形如

{ id: "UserInfo:1004", generated: false, ...}

真实的 UserTimeline:260.userInfo 存储在一个名为 UserInfo:1004 的 reducer 中。而 UserInfo:1004 可能也并不完整,因为它内部也可能存在嵌套,也需要经历这样的一次搜寻过程。要一直递归下去,我们才能得到最终的完整数据。

id 的生成规则

Updating the Store | Apollo React Docs

根据官方文档的说法,apollo 在创建 apollo client 时,可选设置 dataIdFromObject。

const client = new ApolloClient({
    networkInterface,
    dataIdFromObject: x => `${x.__typename}:${x.id}`,
});

如果不设置 dataIdFromObject ,其默认就是 ${x.__typename}:${x.id}
如果 x 不存在 id,则可能出现 ${__typename}:${id}.${property}.${subProperty}








文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/91920.html

相关文章

  • 21 分钟 apollo-client 系列:修改本地 store 数据

    摘要:分钟学是一个系列,简单暴力,包学包会。搭建端,集成使用来获取数据修改本地的数据提供定制方案请求拦截封装修改的存储细节写入的失败原因分析和解决方案修改本地数据之前我们已经知道,我们可以在请求结束之后,通过自动执行的回调,修改。 21 分钟学 apollo-client 是一个系列,简单暴力,包学包会。 搭建 Apollo client 端,集成 redux使用 apollo-clien...

    617035918 评论0 收藏0
  • 21 分钟 apollo-client 系列:简单搭建

    摘要:分钟学是一个系列,简单暴力,包学包会。其中提到了等需要后端配合的东西,徒增了配置的复杂性。如果不行,再跟随我的简单步骤试试。环境要求请确保你已经搭建了自己的环境下文在行号前添加表示删除的原代码,表示新增的代码。 21 分钟学 apollo-client 是一个系列,简单暴力,包学包会。 搭建 Apollo client 端,集成 redux使用 apollo-client 来获取数据...

    ranwu 评论0 收藏0
  • 21 分钟 apollo-client 系列:写入失败的原因和解决方案

    摘要:分钟学是一个系列,简单暴力,包学包会。一旦你丢失了,可能会导致写入失败,或者尽管写入了,但本该携带的那一层的数据没有写入。 21 分钟学 apollo-client 是一个系列,简单暴力,包学包会。 搭建 Apollo client 端,集成 redux使用 apollo-client 来获取数据修改本地的 apollo store 数据提供定制方案 请求拦截 封装修改 clie...

    Baoyuan 评论0 收藏0
  • 21 分钟 apollo-client 系列:扩展 ApolloClient 的 api

    摘要:分钟学是一个系列,简单暴力,包学包会。那怎么办呢本章就教你非常简单地实现扩展的。我们可以借鉴的的写法,为的实例添加一些自己的方法。更重要的是,也会有的效果,上一个的输出会成为下一个的输入,便于组合。 21 分钟学 apollo-client 是一个系列,简单暴力,包学包会。 搭建 Apollo client 端,集成 redux使用 apollo-client 来获取数据修改本地的 ...

    levy9527 评论0 收藏0
  • 21 分钟 apollo-client 系列:请求拦截和 FragmentMatcher

    摘要:分钟学是一个系列,简单暴力,包学包会。接管了请求和状态管理。一般在生产环境中,我们通常还希望做权限验证请求拦截等事务处理。 21 分钟学 apollo-client 是一个系列,简单暴力,包学包会。 搭建 Apollo client 端,集成 redux使用 apollo-client 来获取数据修改本地的 apollo store 数据提供定制方案 请求拦截 封装修改 clie...

    Eastboat 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<