摘要:分鐘學是一個系列,簡單暴力,包學包會。一旦組件掛載后,會自動進行數據請求,前提是客戶端提供的和后端的相符。如果回調返回直接不作請求。在組件內進行分頁請求之前提到了,這個裝飾器為添加了對象,其中有個函數為。
使用 Apollo 獲取數據21 分鐘學 apollo-client 是一個系列,簡單暴力,包學包會。
搭建 Apollo client 端,集成 redux
使用 apollo-client 來獲取數據
修改本地的 apollo store 數據
提供定制方案請求攔截
封裝修改 client 的 api
apollo store 存儲細節
寫入 store 的失敗原因分析和解決方案
推薦先看:GraphQL 入門: 連接到數據
本文只做補充。
下面編寫一個最簡單的 Container,觀察是否能 query 到數據。
container.jsx
import React, { PureComponent } from "react"; import { graphql } from "react-apollo"; import query from "./query.gql"; @graphql(query) export default class ApolloContainer extends PureComponent { render() { console.log(this.props); returnHello Apollo; } }
@graphql(query) 是 apollo 提供的高階組件,以裝飾器的形式包裹你的組件。這里是最簡單的情況,只傳一個 query。
query 語法基本的 query 語法可以參看官方文檔 Queries and Mutations | GraphQL,這里提一下 Apollo 特有的一些語法。
query.gql
#import "../gql/pageInfo.gql" #import "@/gql/topic/userTopicEntity.gql" query topic($topicId: Int!, $pageNum: Int = 1) { community { topicEntity { listByTopicId(topicId: $topicId, pageSize: 10, pageNum: $pageNum) { pageInfo { ...pageInfo } edges { ...userTopicEntity } } } } }
前兩行 import 了其它的 fragment。想必你已經知道,GraphQL 主要通過 fragment 來組合分形 Query。一個好的實踐是盡量對業務實體編寫 fragment 以便復用。
代碼脫敏的關系我就不放詳細的 fragment 了。
上一節我們在 webpack 中配置了 graphql-tag/loader,這個 loader 允許你將 query 、fragment 這些 schema 字符串,以 .gql 文件的形式保存,在 import 時轉化成 js 代碼。
其余部分,基本上和 GraphQL 原生寫法是一樣的,注意幾個點:
一次請求只能包含一個 query,而且不能包含未使用的 fragment。
#import 語法是 loader 提供的,語法和 js 的 import 差不多,除了不能解構 。
如果你 webpack 配置了 alias 就能使用第二行那種寫法。注意,它會把該文件內所有的內容都 import 進來,所以不能在一個 gql 文件里寫多個 query 或 fragment。
對了,為了最小化實踐,你可以先寫不帶參數的 query。也先不要寫 union type。
props.data 的數據結構這樣就好了嗎,是的。一旦組件掛載后,會自動進行數據請求,前提是客戶端提供的 query schema 和后端的相符。
如果請求成功后,會發生什么事情呢?我們可以查看 this.props 打出的 log 來驗證:
// this.props { // .... data: { // ... community: { ... }, // 這是獲取到的數據,結構和你提供的 query schema 一致 loading: false, // 請求過程中為 true networkStatus: 7, // 從 0-8,具體值的含義看這個文件 https://github.com/apollographql/apollo-client/blob/master/src/queries/networkStatus.ts variables: { ... }, // 請求時所用的參數 fetchMore, // 一個函數,用于在組件內「繼續請求」,一般用于分頁請求 refetch, // 函數,用于組件內「強制重新請求」 updateQuery, // 請求成功后立即調用,用于更新本地 store } }高級請求
我們僅改寫裝飾器部分
@graphql(query, { skip: props => !isValid(props), options: props => ({ variables: { topicId: getIdFromUrl(), }, }), })
其中
skip 和 shouldComponentUpdate 的效果是一樣的,決定是否 re-fetch。如果回調返回 false 直接不作請求。
options 返回一個函數,用以設置請求的細節,比如 variables 用于設置 query 參數
更詳細的文檔可以查閱
API: graphql container with queries | Apollo React Docs
GraphQL 入門: Apollo Client - 連接到數據
分頁請求如文檔 Pagination | Apollo React Docs 所說,Apollo 支持兩種分頁
offset-based按條數偏移量來請求分頁,請求時提供兩個參數
limit:相當于 pageSize,一頁最多取多少個
offset: 條數偏移量,第 n 頁的 offset = limit * n
可見你需要自己維護一個 pageNum: n 來實現按頁碼分頁
cursor-based這是 Relay 風格的請求,cursor 用于記錄下個請求開始時,返回的第一個元素的位置,一般可以用該元素的 id 來標識。
RESTful 風格我們后端并沒有采取上面任何一種,而是提供了一個 pageInfo 對象,由前端傳入所需參數,保持和 RESTful api 相似的風格。
query.gql
#import "../gql/pageInfo.gql" #import "@/gql/topic/userTopic.gql" query topic($topicId: Int!, $pageNum: Int = 1) { community { topicEntity { listByTopicId(topicId: $topicId, pageSize: 10, pageNum: $pageNum) { pageInfo { ...pageInfo } edges { ...userTopicEntity } } } } }
pageInfo.gql
fragment pageInfo on PageInfo { pageNum # 頁碼 pageSize # 每頁條數 pages # 總頁數 total # 總條數 }
聲明下,由于我們只使用 GraphQL 的 Query 功能,所以沒研究過這種格式是否會影響 Mutation。現在或以后有 Mutation 需求的,盡量采用官方推薦的前兩種吧。
在組件內進行分頁請求之前提到了, graphql 這個裝飾器為 this.props 添加了 data 對象,其中有個函數為 fetchMore。
fetchMore 看名字就知道是用來作分頁請求的。
下面我們看一個比較真實的例子,許多業務相關的代碼都用表示其作用的函數替代了,注意看注釋:
import React, { PureComponent } from "react"; import { graphql } from "react-apollo"; import { select } from "./utils"; // 注意,這里用的 query 是 「RESTful 風格」那一節中貼出的 schema import query from "./query.gql"; @graphql(query, { skip: props => !isValid(props), options: props => ({ variables: { topicId: getIdFromUrl(), }, }), }) @select({ // 你可以寫一個函數,從 this.props.data 里過濾出當前列表的 pageInfo,直接添加到 this.props.pageInfo pageInfo: getPathInfoFromProps(props), }) export default class TopicListContainer extends PureComponent { hasMore = () => { const { pageNum = 0, pages = 0 } = this.props.pageInfo || {}; return pageNum < pages; } loadNextPage = () => { const { pageInfo = {}, data } = this.props; const { pageNum = 1 } = pageInfo; const fetchMore = data && data.fetchMore; if (!this.hasMore()) return; if (!fetchMore) return; return fetchMore({ variables: { // 是的,這里不需要把你在 `@graphql` 裝飾器中定義的其它 variables 再寫一遍 // apollo 會自動 merge pageNum: pageNum + 1, }, // 這個回調函數,會在 fetch 成功后自動執行,用于修改本地 apollo store updateQuery: (prev, { fetchMoreResult }) => { if (!fetchMoreResult) return prev; // 嘗試 log 下 `fetchMoreResult`,其返回的數據結構,和 query 中的 schmea 是一致的 // parseNextData 返回新數據。 // 新數據的數據結構必須和 query schema 一樣 // NOTE: 此處會有大坑,如果你發現最終數據并未改變,請閱讀后文 return parseNextData(prev, fetchMoreResult); } }); } render() { return (); } }
updateQuery 中,使用 parseNextData 經過一些處理,返回新數據給 apollo,apollo 將把它寫入到 apollo store 中。
注意,這里至少會有兩處大坑
如果寫入失敗,是會靜默失敗的,也就是說 沒有任何報錯提示
如果寫入數據的結構,和 query schema 不符,就會寫入失敗。
但寫入失敗的情況還不止于此!如果你發現最終數據并未改變,可能是中招了,解毒方案 請閱讀 寫入 store 的失敗原因分析和解決方案
這段代碼只演示了如何 被動 地去修改本地的 apollo store 數據,要問如何 主動 去修改 apollo store,請看這篇文章: 修改本地的 apollo store 數據
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/91924.html
摘要:分鐘學是一個系列,簡單暴力,包學包會。那怎么辦呢本章就教你非常簡單地實現擴展的。我們可以借鑒的的寫法,為的實例添加一些自己的方法。更重要的是,也會有的效果,上一個的輸出會成為下一個的輸入,便于組合。 21 分鐘學 apollo-client 是一個系列,簡單暴力,包學包會。 搭建 Apollo client 端,集成 redux使用 apollo-client 來獲取數據修改本地的 ...
摘要:分鐘學是一個系列,簡單暴力,包學包會。其中提到了等需要后端配合的東西,徒增了配置的復雜性。如果不行,再跟隨我的簡單步驟試試。環境要求請確保你已經搭建了自己的環境下文在行號前添加表示刪除的原代碼,表示新增的代碼。 21 分鐘學 apollo-client 是一個系列,簡單暴力,包學包會。 搭建 Apollo client 端,集成 redux使用 apollo-client 來獲取數據...
摘要:分鐘學是一個系列,簡單暴力,包學包會。一旦你丟失了,可能會導致寫入失敗,或者盡管寫入了,但本該攜帶的那一層的數據沒有寫入。 21 分鐘學 apollo-client 是一個系列,簡單暴力,包學包會。 搭建 Apollo client 端,集成 redux使用 apollo-client 來獲取數據修改本地的 apollo store 數據提供定制方案 請求攔截 封裝修改 clie...
摘要:分鐘學是一個系列,簡單暴力,包學包會。內部通過自己的私有沒有暴露給開發者來更新這個。相當于這個就是自己維護的,它將所有通過得到的數據保存在這里。的生成規則根據官方文檔的說法,在創建時,可選設置。如果不存在,則可能出現。 21 分鐘學 apollo-client 是一個系列,簡單暴力,包學包會。 搭建 Apollo client 端,集成 redux使用 apollo-client 來...
摘要:分鐘學是一個系列,簡單暴力,包學包會。接管了請求和狀態管理。一般在生產環境中,我們通常還希望做權限驗證請求攔截等事務處理。 21 分鐘學 apollo-client 是一個系列,簡單暴力,包學包會。 搭建 Apollo client 端,集成 redux使用 apollo-client 來獲取數據修改本地的 apollo store 數據提供定制方案 請求攔截 封裝修改 clie...
閱讀 2406·2021-09-22 15:15
閱讀 648·2021-09-02 15:11
閱讀 1793·2021-08-30 09:48
閱讀 1894·2019-08-30 15:56
閱讀 1498·2019-08-30 15:52
閱讀 2050·2019-08-30 15:44
閱讀 441·2019-08-29 16:29
閱讀 1545·2019-08-29 11:06