React Native项目使用react-apollo实现更新缓存的两种方式

更新日期: 2019-02-19阅读: 2.7k标签: native

背景:

举个例子:在显示动态的页面中删除某一条动态之后退出该页,当再进入该页之后这个被删除的动态是否还显示?
显示! 为啥? cache!
cache是为了增强用户体验,如果每一次进入一个页面都需要从网络获取数据,当数据量很大时却迟迟加载不出来,麻爪了吧.....
但是现在cache的存在却给我们造成了很大的困扰:
我虽然删除了这条动态,并配合使用react-native的state进行状态变化将这个动态在视觉上被删除掉了,但我没有重新获取数据,更新数据。当我从外界再次进入这个页面之后页面上显示的数据还是从cache中获取的数据。因此必须要更新cache!!

在前面的博客中提到,GraphQL是一个api查询语言,他可以将使用PostgreSQL写的server代码自动生成Query或者Mutation,非常的方便。而Apollo Client就是一个强大的JavaScript GraphQL客户端。对于cache,在Apollo Client中有着强大的管理策略。
在近阶段的使用过程中,我总结了两种管理缓存的办法:

  1. 手动更新缓存
  2. 自动更新缓存


一:手动更新缓存

在不断的搜索中我在文档中找到了他:
https://www.apollographql.com...

一个可以自定义访问,或者直接访问apollo缓存的指南

看到这的时候我似乎有些明白了,人家都给你说的很明白了。你管理缓存的方式有两种一种是自定义,另一种是自动。
fuck。武林秘籍都放在这,我却因为看不懂武林秘籍上的字迟迟不能升级????
应用场景:
如图一个消息隐藏的选择开关,当进行选择之后就会自动触发react-apollo的mutation操作,将这种变化传递到数据库,但是如果不更新缓存,当你退出本页面,再进来时就会发现消息隐藏的开关显示和原来还是一样的。因此需要进行缓存的更新。
第一段代码:GraphQL定义mutation

export const UPDATE_PERSON_SETTING = gql`
mutation updatePersonById($input: UpdatePersonByIdInput!) {
  updatePersonById(input: $input) {
    clientMutationId
    person {
    hideSpeaker
    }
  }
}
`

第二段代码: Mutation组件mutate操作
(请先阅读官网相关部分之后再看)

<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将数据从服务器获取到了。

当然据官网上的描述,手动更改缓存的方式还有几种,但是目前还没有仔细的看过。日后再进行解释说明。


二:自动更新缓存

与手动更新相对的自然就是自动更新了。
既然有自动更新功能,他肯定是借助了什么逆天的“工具”!

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:难,都难。爬,一起爬。


来自:https://segmentfault.com/a/1190000018196892


链接: https://www.fly63.com/article/detial/2058

来聊聊怎么写react-native上的样式吧

在react-native上是怎么写样式的吧,和传统的web不一样的是,在react-native上面是没有css代码,不过得益于Yoga,我们可以在客户端上像写css一样的去书写我们的样式。

WKWebView 里 JS 和 native 通信的例子

初始化 wkwebview,设置 message handler,native 端注册了 testecho 的messageHandler,实现 WKScriptMessageHandler协议,执行JS 代码 ,所以 JS 可以通过 window.webkit.messageHandlers.testecho.postMessage 来回调客户端,和文档中说的一样

由使用request-promise-native想到的异步处理方法

因为js语言的特性,使用node开发程序的时候经常会遇到异步处理的问题。对于之前专长App开发的我来说,会纠结node中实现客户端API请求的“最佳实践”。下面以OAuth2.0为场景,需要处理的流程:获取access token、使用获取到的token,发起API请求、处理API数据

11个React Native组件库

React Native 是 Facebook 2015年开源的 Javascript 框架,旨在使用 Javascript 高效开发手机端 App。根据大众的需求,我们列出了一个有用的React-Native UI库列表,可以帮助你更好地入门React Native。

React Native 传参的几种方式

在React Native 中由于业务的需要, 我们往往要在诸多的页面间,组件之间做一些参数的传递与管理, 在这里我总结了几大经过验证,稳定好用的方式给大家

如何正确选型,React Native 还是 Native?

随着 H5 标准的发布以及推广,使得移动应用的开发也受到了很大影响,出于效率、成本等原因,移动应用的开发不再完全依赖于 “原生”。近日越发火热的混合应用(Hybrid App)介于 Web 应用和原生应用之间

react-native报错Cannot get property packageName on null object

react-native打包安卓apk的时候,报错Cannot get property packageName on null object,完全没有头绪,研究了半天才发现竟然是因为package.json里面scripts自定了命令导致的,无法理解为何会影响安卓打包并且报错packageName null

React Native 添加 Redux 支持

之前写的项目都是人家编写好的脚手架,里面包含项目所需的环境文件,但由于有些东西用不到打包增加软件体积,所以自己从头搭建个环境。是基于 Native Base + react-navigation + Redux 的 React Native 脚手架,现在项目环境如下

Flutter platform view 使用篇

Flutter作为备受关注的跨平台的开发框架,长远来看,前景肯定是比较好的,在其基础组件还未完善与成熟之前,能够高效的复用现有的native组件,是比较合适的方案。官方提供了Plugin的方式,允许将一个成熟的native组件(比如mapview)

JSBridge 初探

近些年,移动端普及化越来越高,开发过程中选用 Native 还是 H5 一直是热门话题。Native 和 H5 都有着各自的优缺点,为了满足业务的需要,公司实际项目的开发过程中往往会融合两者进行 Hybrid 开发。Native 和 H5 分处两地,看起来无法联系,那么如何才能让双方协同实现功能呢?

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!