21 分鐘學 apollo-client 是一個系列,簡單暴力,包學包會。javascript
搭建 Apollo client 端,集成 redux
使用 apollo-client 來獲取數據
修改本地的 apollo store 數據
提供定製方案html
Apollo 僅僅是在 Redux 下開闢了一個 reducer,好比就叫 apollo
。apollo 內部經過本身的私有 action (沒有暴露給開發者)來更新這個 reducer 。
至關於這個 reducer 就是 Apollo 本身維護的 store ,它將全部經過 GraphQL query 獲得的數據保存在這裏。react
咱們只能經過如下幾種辦法來修改 apollo storeredux
updateQuery
回調修改 store第二種方式,雖然接口是命令式的,但並非直接修改 state 的值,背後本質是在調用它內部私有的 action ,最終仍是以 dispatch 的形式修改 store。只是這個過程對開發者是屏蔽的。
固然你必須提供對應的 GraphQL Schema (一段用 gql 語法描述的 query 或 fragment),最終的數據結構若是不符合 Schema ,會 靜默 失敗。
更具體的解釋和運用,看 修改本地的 apollo store 數據 一節。segmentfault
可能你會問,既然 Apollo 的 store 是存在 redux 的 store 中的,本身寫 reducer 去改不就行了嗎?
這很容易想到,但不容易實現。後端
咱們看看 apollo store 中數據存儲的結構:api
很像 normalizr
對不對?緩存
簡單說,apollo store 中存儲的是扁平化的緩存。數據結構
當你想要直接修改 reducer 數據時,你須要
__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, 它的 __typename
是 UserInfo
,那麼 UserTimeline:260
下的 userInfo
中存儲只是對應的 reducer 索引,形如
{ id: 'UserInfo:1004', generated: false, ...}
真實的 UserTimeline:260.userInfo
存儲在一個名爲 UserInfo:1004
的 reducer 中。而 UserInfo:1004
可能也並不完整,由於它內部也可能存在嵌套,也須要經歷這樣的一次搜尋過程。要一直遞歸下去,咱們才能獲得最終的完整數據。
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}
。