React Native項目使用react-apollo實現更新緩存的兩種方式

背景:

舉個例子:在顯示動態的頁面中刪除某一條動態以後退出該頁,當再進入該頁以後這個被刪除的動態是否還顯示?
顯示! 爲啥? cache
cache是爲了加強用戶體驗,若是每一次進入一個頁面都須要從網絡獲取數據,當數據量很大時卻遲遲加載不出來,麻爪了吧.....
可是如今cache的存在卻給咱們形成了很大的困擾:
我雖然刪除了這條動態,並配合使用react-nativestate進行狀態變化將這個動態在視覺上被刪除掉了,但我沒有從新獲取數據,更新數據。當我從外界再次進入這個頁面以後頁面上顯示的數據仍是從cache中獲取的數據。所以必需要更新cache!!html

在前面的博客中提到,GraphQL是一個API查詢語言,他能夠將使用PostgreSQL寫的server代碼自動生成Query或者Mutation,很是的方便。而Apollo Client就是一個強大的JavaScript GraphQL客戶端。對於cache,在Apollo Client中有着強大的管理策略。
在近階段的使用過程當中,我總結了兩種管理緩存的辦法:react

  1. 手動更新緩存
  2. 自動更新緩存

一:手動更新緩存

在不斷的搜索中我在文檔中找到了他:
https://www.apollographql.com...
在這裏插入圖片描述數據庫

一個能夠自定義訪問,或者直接訪問apollo緩存的指南

看到這的時候我彷佛有些明白了,人家都給你說的很明白了。你管理緩存的方式有兩種一種是自定義,另外一種是自動。
fuck。武林祕籍都放在這,我卻由於看不懂武林祕籍上的字遲遲不能升級????
應用場景:
如圖一個消息隱藏的選擇開關,當進行選擇以後就會自動觸發react-apollomutation操做,將這種變化傳遞到數據庫,可是若是不更新緩存,當你退出本頁面,再進來時就會發現消息隱藏的開關顯示和原來仍是同樣的。所以須要進行緩存的更新。
在這裏插入圖片描述
第一段代碼: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,就必須進行嚴格的限制,確保從cachereadQuery出來的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.0apollo-cache-inmemory 他是默認實現的。所以,只要使用了Apollo Client 2.0npm時他是會進行相應的自動安裝的。
緩存的標準化管理是實現自動更新緩存的前提!!!
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:難,都難。爬,一塊兒爬。

相關文章
相關標籤/搜索