摘要:分鐘學是一個系列,簡單暴力,包學包會。搭建端,集成使用來獲取數(shù)據(jù)修改本地的數(shù)據(jù)提供定制方案請求攔截封裝修改的存儲細節(jié)寫入的失敗原因分析和解決方案修改本地數(shù)據(jù)之前我們已經(jīng)知道,我們可以在請求結束之后,通過自動執(zhí)行的回調,修改。
修改本地 store 數(shù)據(jù)21 分鐘學 apollo-client 是一個系列,簡單暴力,包學包會。
搭建 Apollo client 端,集成 redux
使用 apollo-client 來獲取數(shù)據(jù)
修改本地的 apollo store 數(shù)據(jù)
提供定制方案請求攔截
封裝修改 client 的 api
apollo store 存儲細節(jié)
寫入 store 的失敗原因分析和解決方案
之前我們已經(jīng)知道,我們可以在請求結束之后,通過自動執(zhí)行 fetchMore 的 updateQuery 回調,修改 apollo store。
那么,如何在不觸發(fā)請求的情況下,主動修改 apollo store 呢?
也許你會說通過 redux 的方式,dispatch 一個 action,由 reducer 來處理,但因為 apollo store 的數(shù)據(jù)存儲方案,這會相當麻煩。
詳細原理請看這一小節(jié) apollo store 存儲細節(jié)
Apollo 對此,提供了兩組命令式 api read/writeQuery 和 read/writeFragment
詳見其文檔:DataProxy
或者這篇中文文檔:GraphQL 入門: Apollo Client 存儲API
讀完這兩篇文檔,你大概就能掌握修改 apollo store 的技巧。
不過其中還是有不少值得注意的點,下面通過代碼和注釋來體會:
import React, { PureComponent } from "react"; import TodoQuery from "./TodoQuery"; import TodoFragment form "./TodoFragment"; import { withApollo, graphql } from "react-apollo"; @graphql(TodoQuery) @withApollo // 通過 props 讓組件可以訪問 client 實例 class TodoContainer extends PureComponent { handleUpdateQuery = () => { const client = this.props.client; const variables = { id: 5 }; const data = client.readQuery({ variables, query: TodoQuery, }); const nextData = parseNextData(data); client.writeQuery({ variables, query: TodoQuery, data: nextData, }); } handleUpdateFragment = () => { const client = this.props.client; const data = client.readFragment({ id: "Todo:5", fragment: TodoFragment, fragmentName: "todo", // fragment 的名字,必填,否則可能會 read 失敗 }); const nextData = parseNextData(data); client.writeFragment({ id: "Todo:5", fragment: TodoFragment, fragmentName: "todo", data: nextData, }); } }
不過,還是需要注意,它們和 fetchMore 里的 updateQuery 一樣,都存在靜默失敗和寫入限制。
如果你發(fā)現(xiàn)數(shù)據(jù)沒有被更新,嘗試看我給出的解讀和解毒方案: 寫入 store 的失敗原因分析和解決方案
你可能還注意到了 read/writeFragment 時,其 id 并不是簡單的 5,而是 ${__typename}:5 。
這和 apollo store 存儲數(shù)據(jù)的方式有關,我在 apollo store 存儲細節(jié) 詳述了 apollo store 存儲數(shù)據(jù)的原理。
在此處,你只需要知道,這里 id 的值應當與你在創(chuàng)建 apollo client 時設置的 dataIdFromObject 有關,如果沒有設置,默認為 ${__typename}:${data.id}。
最好的方式是調用 client.dataIdFromObject 函數(shù)計算出 id
const { id, __typename } = data; const id = client.dataIdFromObject({ id, __typename, });簡化接口
不過你不覺得上面這種寫法相當麻煩嗎?
雖然先 read 再 write 比較原子化,但是考慮到大部分場景下我們只需要 update 就可以了,參數(shù)這么傳來傳去相當麻煩,更不用說會寫太多重復的代碼。
所以咱們可以寫一個 updateQuery、updateFragment 函數(shù)。
enhancers.js
import client from "./client"; function updateFragment(config) { const { id: rawId, typename, fragment, fragmentName, variables, resolver } = config; // 默認使用 fragmentName 作為 __typename const __typename = typename || toUpperHeader(fragmentName); const id = client.dataIdFromObject({ id: rawId, __typename, }); const data = client.readFragment({ id, fragment, fragmentName, variables }); const nextData = resolver(data); client.writeFragment({ id, fragment, fragmentName, variables, data: nextData, }); return nextData; } function updateQuery(config) { const { variables, query, resolver } = config; const data = client.readQuery({ variables, query }); const nextData = resolver(data); client.writeQuery({ variables, query, data: nextData, }); return nextData; }; function toUpperHeader(s = "") { const [first = "", ...rest] = s; return [first.toUpperCase(), ...rest].join(""); }
如此,我們可以這樣簡化之前的代碼
import React, { PureComponent } from "react"; import TodoQuery from "./TodoQuery"; import TodoFragment form "./TodoFragment"; import { withApollo, graphql } from "react-apollo"; import { updateQuery, updateFragment } from "@/apollo/enhancers"; @graphql(TodoQuery) @withApollo // 通過 props 讓組件可以訪問 client 實例 class TodoContainer extends PureComponent { handleUpdateQuery = () => { return updateQuery({ variables: { id: 5 }, query: TodoQuery, resolver: data => parseNextData(data), }); } handleUpdateFragment = () => { return updateFragment({ id: 5, typename: "Todo", fragment: TodoFragment, fragmentName: "todo", resolver: data => parseNextData(data); }); } }
其中,resolver 是一個數(shù)據(jù)處理函數(shù),它接收 read 操作后的 data ,返回的 nextData 將用于 write 操作。
這種簡單的 update 場景其實是更常見的,且你仍然可以在 resolver 中進行 debug,可以說代碼相當精簡了。
在 封裝修改 client 的 api 里我們提到可以使用 enhancer 的方式為 client 添加接口,如果你懶得每次都 import 這兩個函數(shù),那么不妨將他們注冊為 client 的實例方法:
enhancers.js
const enhancers = [ updateFragmentFactory, updateQueryFactory, ]; export default function applyEnhancers(client) { // 更函數(shù)式的寫法是把 enhancers 也作為參數(shù)傳進來,但是我需要的 enhancer 比較少,做此精簡 return enhancers.reduce( (result, enhancer) => enhancer(result), client ); } // --- enhancers --- function updateFragmentFactory(client) { return function updateFragment(config) { // ... } return client; } function updateQueryFactory(client) { return function updateQuery(config) { // ... }; return client; }
這樣你就可以直接從 client 實例中訪問這兩個函數(shù)了。
提示:在組件中只需 withApollo 即可添加 client 到 props 中。
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/91921.html
摘要:分鐘學是一個系列,簡單暴力,包學包會。內部通過自己的私有沒有暴露給開發(fā)者來更新這個。相當于這個就是自己維護的,它將所有通過得到的數(shù)據(jù)保存在這里。的生成規(guī)則根據(jù)官方文檔的說法,在創(chuàng)建時,可選設置。如果不存在,則可能出現(xiàn)。 21 分鐘學 apollo-client 是一個系列,簡單暴力,包學包會。 搭建 Apollo client 端,集成 redux使用 apollo-client 來...
摘要:分鐘學是一個系列,簡單暴力,包學包會。一旦你丟失了,可能會導致寫入失敗,或者盡管寫入了,但本該攜帶的那一層的數(shù)據(jù)沒有寫入。 21 分鐘學 apollo-client 是一個系列,簡單暴力,包學包會。 搭建 Apollo client 端,集成 redux使用 apollo-client 來獲取數(shù)據(jù)修改本地的 apollo store 數(shù)據(jù)提供定制方案 請求攔截 封裝修改 clie...
摘要:分鐘學是一個系列,簡單暴力,包學包會。一旦組件掛載后,會自動進行數(shù)據(jù)請求,前提是客戶端提供的和后端的相符。如果回調返回直接不作請求。在組件內進行分頁請求之前提到了,這個裝飾器為添加了對象,其中有個函數(shù)為。 21 分鐘學 apollo-client 是一個系列,簡單暴力,包學包會。 搭建 Apollo client 端,集成 redux使用 apollo-client 來獲取數(shù)據(jù)修改本...
摘要:分鐘學是一個系列,簡單暴力,包學包會。那怎么辦呢本章就教你非常簡單地實現(xiàn)擴展的。我們可以借鑒的的寫法,為的實例添加一些自己的方法。更重要的是,也會有的效果,上一個的輸出會成為下一個的輸入,便于組合。 21 分鐘學 apollo-client 是一個系列,簡單暴力,包學包會。 搭建 Apollo client 端,集成 redux使用 apollo-client 來獲取數(shù)據(jù)修改本地的 ...
摘要:分鐘學是一個系列,簡單暴力,包學包會。其中提到了等需要后端配合的東西,徒增了配置的復雜性。如果不行,再跟隨我的簡單步驟試試。環(huán)境要求請確保你已經(jīng)搭建了自己的環(huán)境下文在行號前添加表示刪除的原代碼,表示新增的代碼。 21 分鐘學 apollo-client 是一個系列,簡單暴力,包學包會。 搭建 Apollo client 端,集成 redux使用 apollo-client 來獲取數(shù)據(jù)...
閱讀 3242·2021-10-21 17:50
閱讀 3254·2021-10-08 10:05
閱讀 3380·2021-09-22 15:04
閱讀 581·2019-08-30 14:00
閱讀 1939·2019-08-29 17:01
閱讀 1508·2019-08-29 15:16
閱讀 3219·2019-08-26 13:25
閱讀 852·2019-08-26 11:44