舉個例子:在顯示動態的頁面中刪除某一條動態以後退出該頁,當再進入該頁以後這個被刪除的動態是否還顯示?
顯示! 爲啥? 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:難,都難。爬,一塊兒爬。