举个例子:在显示动态的页面中删除某一条动态以后退出该页,当再进入该页以后这个被删除的动态是否还显示?
显示! 为啥? cache
!cache
是为了加强用户体验,若是每一次进入一个页面都须要从网络获取数据,当数据量很大时却迟迟加载不出来,麻爪了吧.....
可是如今cache
的存在却给咱们形成了很大的困扰:
我虽然删除了这条动态,并配合使用react-native
的state
进行状态变化将这个动态在视觉上被删除掉了,但我没有从新获取数据,更新数据。当我从外界再次进入这个页面以后页面上显示的数据仍是从cache
中获取的数据。所以必需要更新cache
!!html
在前面的博客中提到,GraphQL
是一个API
查询语言,他能够将使用PostgreSQL
写的server
代码自动生成Query
或者Mutation
,很是的方便。而Apollo Client
就是一个强大的JavaScript GraphQL
客户端。对于cache
,在Apollo Client
中有着强大的管理策略。
在近阶段的使用过程当中,我总结了两种管理缓存的办法:react
在不断的搜索中我在文档中找到了他:
https://www.apollographql.com...数据库
一个能够自定义访问,或者直接访问apollo缓存的指南
看到这的时候我彷佛有些明白了,人家都给你说的很明白了。你管理缓存的方式有两种一种是自定义,另外一种是自动。
fuck。武林秘籍都放在这,我却由于看不懂武林秘籍上的字迟迟不能升级????
应用场景:
如图一个消息隐藏的选择开关,当进行选择以后就会自动触发react-apollo
的mutation
操做,将这种变化传递到数据库,可是若是不更新缓存,当你退出本页面,再进来时就会发现消息隐藏的开关显示和原来仍是同样的。所以须要进行缓存的更新。
第一段代码:GraphQL定义mutationnpm
export const UPDATE_PERSON_SETTING = gql` mutation updatePersonById($input: UpdatePersonByIdInput!) { updatePersonById(input: $input) { clientMutationId person { hideSpeaker } } } `
第二段代码: Mutation组件mutate操做
(请先阅读官网相关部分以后再看)react-native
<Mutation mutation={UPDATE_PERSON_SETTING} variables={{ input: { id: currentPerson.id, personPatch: { hideSpeaker: true } } } } update={(cache, { data: { updatePersonById } }) => { this.updateCacheAfterSwitchHideSpeak(cache, updatePersonById.person.hideSpeaker) } } > {updatePersonById => ( <Switch value={currentPerson.hideSpeaker} onValueChange={value => { updatePersonById({ variables: { input: { id: currentPerson.id, personPatch: { hideSpeaker: value } } } }) }} /> )} </Mutation>
分析:
采用UPDATE_PERSON_SETTING
这段GraphQL mutation
操做在对开关进行更改,同时返回了更改后的数据hideSpeaker
。
在Mutation
这个组件中第三个参数update
是一个箭头函数,函数的第一个参数是cache
,第二个参数data是用来更改缓存的数据。这个data
就来自于第一段代码中mutation
操做的返回值。
在函数体中,调用用于更改缓存的函数updateCacheAfterSwitchHideSpeak
,一并将cache和data
传入其中。
接下来分析一下第三段代码
第三段代码:更新缓存函数缓存
updateCacheAfterSwitchHideSpeak = (cache, value) => { const data = cache.readQuery({ query: CURRENT_PERSON }) data.currentPerson.hideSpeaker = value cache.writeQuery({ query: CURRENT_PERSON, data }) }
当接收到cache和value
以后,输出一下cache
,发现里面存在两个方法:readQuery,writeQuery
,这两个方法就是咱们用来进行读取缓存和更改缓存的办法。
注意:
这里的query
参数必需要和渲染这个组件时所获取数据的query
来源是一致的。
也就是说,必须是同一个GraphQL API
。若是存在variables
,那么variables
也必须是同样的。
结合实际状况:在进入这个设置页面时,经过调用一个GraphQL
查询API
而且将hideSpeaker
查询出来,渲染出页面。而查询的结果也就造成了一个缓存。一个项目中有不少的查询,有些页面使用同一个GraphQL API
进行查询,可是他们的condition
却不一样这就会形成cache
的不一样,所以在查询过程当中若是存在variables
,就必须进行严格的限制,确保从cache
中readQuery
出来的data
就是你求之不得的那个Ta -_-。
下面是一段带有variables的readQuery代码。服务器
const variables = { personPostCondition: { personId: personId }, likeCondition: { personId: personId }, orderBy: 'CREATED_AT_DESC' } const data = cache.readQuery({ variables, query: PERSON_DYNAMICS })
在读取完cache
中的data
以后,你能够输出一下,看是否是当时你在渲染页面时query
的数据,可是此时消息隐藏已经进行了调整,相应的hideSpeaker
却仍是false
,此时单独将这个属性拿出来进行调整:data.currentPerson.hideSpeaker = value
在修改完后再使用writeQuery
将新的cache
写进去。此时就完成了cache
的更改。网络
query和readQuery的区别query
的数据查询来源有两个:
1:服务器
2:缓存readQuery
的数据查询来源只有一个:
1:缓存
若是缓存中不存在,他就会报错,所以使用这个方法的前提就是已经使用了query
将数据从服务器获取到了。ide
固然据官网上的描述,手动更改缓存的方式还有几种,可是目前尚未仔细的看过。往后再进行解释说明。函数
与手动更新相对的天然就是自动更新了。
既然有自动更新功能,他确定是借助了什么逆天的“工具”!
apollo-cache-inmemory
这一点在官网也已经有了详细的说明了:
安排的明明白白的了,在Apollo Client 2.0
中apollo-cache-inmemory
他是默认实现的。所以,只要使用了Apollo Client 2.0
在npm
时他是会进行相应的自动安装的。
缓存的标准化管理是实现自动更新缓存的前提!!!inmemory
是一个规范化的数据存储,他是咋规范化的呢???
在query
到数据以后,InMemoryCache
对查询来的数据进行分割成单个的对象并保存。
并且为这些单个的对象都设置惟一的标识符,若是在query
数据时将那些能够做为惟一标识符的字段例如id
也一并获取到了,那么就将这个id
做为分割后对象的惟一标识符。
上面这个简单的例子说明,若是id
相同,那么score在
缓存中的数据也会自动进行更新。
所以结合咱们以前的实例作一个简单的更改:
export const UPDATE_PERSON_SETTING = gql` mutation updatePersonById($input: UpdatePersonByIdInput!) { updatePersonById(input: $input) { clientMutationId person { id hideSpeaker } } } `
咱们在进行mutation
以后的返回值中存在id
,这就符合上面的要求。他就会自动进行缓存的更新。
若是你还心存疑虑,你大可在readQuery
后将data
输出一下,此时你就会发现 hideSpeaker
已经更改为目前的状态true
。这就是自动更新的快捷之处。此时你就没必要使用readQuery和writeQuery
这种费时费力的方法了。
1:不管是自动更新仍是手动更新,都必须将更改以后的数据返回出来,就像hideSpeaker
,更改他以后,你必须将它返回出来。这不管是在自动更新仍是在手动更新上都是有必要的。2:关于二者的选择使用,毫无疑问,一般状况下使用自动更新,特殊状况下使用手动更新,在明白原理后,有时你可使用手动更新进行一些投机取巧的更新缓存的操做。3:难,都难。爬,一块儿爬。