在 React 應用程序中使用 Apollo-Client 了解客戶端 GraphQl

已發表: 2022-03-10
快速總結 ↬曾經嘗試過在客戶端應用程序中與 GraphQL 服務器進行交互,並且在到達任何地方之前就想放棄? 曾經因為不知道而拒絕加入需要使用 GraphQL API 的代碼庫的邀請? 曾經覺得自己是唯一一個還沒有學會如何使用 GraphQL API 的前端工程師? 如果您對其中任何一個問題的回答是肯定的,那麼本教程適合您。 我們將仔細研究 GraphQL 和 Apollo Client 的一些基礎知識,以及如何使用它們。 最後,我們將構建一個使用 Apollo Client 的寵物商店應用程序。 然後,您可以繼續構建您的下一個項目。

根據 State of JavaScript 2019,38.7% 的開發者願意使用 GraphQL,而 50.8% 的開發者願意學習 GraphQL。

作為一種查詢語言,GraphQL 簡化了構建客戶端應用程序的工作流程。 它消除了在客戶端應用程序中管理 API 端點的複雜性,因為它公開了一個 HTTP 端點來獲取所需的數據。 因此,它消除了數據的過度獲取和不足,就像在 REST 的情況下一樣。

但 GraphQL 只是一種查詢語言。 為了輕鬆使用它,我們需要一個為我們完成繁重工作的平台。 Apollo 就是這樣一個平台。

Apollo 平台是 GraphQL 的實現,它在雲(服務器)和應用程序的 UI 之間傳輸數據。 當您使用 Apollo 客戶端時,所有用於檢索數據、跟踪、加載和更新 UI 的邏輯都由useQuery鉤子封裝(就像 React 的情況一樣)。 因此,數據獲取是聲明性的。 它還具有零配置緩存。 只需在您的應用程序中設置 Apollo 客戶端,您就可以獲得開箱即用的智能緩存,無需額外配置。

Apollo Client 還可以與其他框架互操作,例如 Angular、Vue.js 和 React。

注意本教程將使那些過去在客戶端使用過 RESTful 或其他形式的 API 並希望了解 GraphQL 是否值得一試的人受益。 這意味著您之前應該使用過 API; 只有這樣,您才能理解 GraphQL 對您的好處。 雖然我們將介紹 GraphQL 和 Apollo Client 的一些基礎知識,但對 JavaScript 和 React Hooks 的深入了解將會派上用場。

GraphQL 基礎知識

本文不是對 GraphQL 的完整介紹,但我們將在繼續之前定義一些約定。

什麼是 GraphQL?

GraphQL 是一種規範,描述了一種聲明式查詢語言,您的客戶可以使用該語言向 API 詢問他們想要的確切數據。 這是通過為您的 API 創建一個強大的類型模式來實現的,具有最大的靈活性。 它還確保 API 解析數據,並根據模式驗證客戶端查詢。 這個定義意味著 GraphQL 包含一些規範,使其成為一種聲明式查詢語言,具有靜態類型的 API(圍繞 Typescript 構建)並使客戶端可以利用這些類型系統向 API 詢問它想要的確切數據.

因此,如果我們創建了一些包含一些字段的類型,那麼,從客戶端,我們可以說,“給我們這些包含這些確切字段的數據”。 然後 API 將以該確切形狀響應,就像我們在強類型語言中使用類型系統一樣。 您可以在我的 Typescript 文章中了解更多信息。

讓我們看看 GraphQl 的一些約定,這些約定將在我們繼續進行時對我們有所幫助。

基礎

  • 運營
    在 GraphQL 中,執行的每個操作都稱為一個操作。 有幾個操作,即:
    • 詢問
      此操作與從服務器獲取數據有關。 您也可以將其稱為只讀提取。
    • 突變
      此操作涉及從服務器創建、更新和刪除數據。 它通常被稱為 CUD(創建、更新和刪除)操作。
    • 訂閱
      GraphQL 中的此操作涉及在發生特定事件時將數據從服務器發送到其客戶端。 它們通常使用 WebSockets 實現。

在本文中,我們將只處理查詢和變異操作。

  • 操作名稱
    您的客戶端查詢和變異操作有唯一的名稱
  • 變量和參數
    操作可以定義參數,非常類似於大多數編程語言中的函數。 然後可以將這些變量作為參數傳遞給操作內的查詢或變異調用。 在客戶端執行操作期間,預計將在運行時給出變量。
  • 別名
    這是客戶端 GraphQL 中的一種約定,涉及用 UI 的簡單易讀的字段名稱重命名冗長或模糊的字段名稱。 在您不希望字段名稱衝突的用例中,別名是必要的。
GraphQL 基本約定
GraphQL 基本約定。 (大預覽)
跳躍後更多! 繼續往下看↓

什麼是客戶端 GraphQL?

當前端工程師使用任何框架(如 Vue.js 或(在我們的例子中)React)構建 UI 組件時,這些組件會根據客戶端上的特定模式進行建模和設計,以適應將從服務器獲取的數據。

RESTful API 最常見的問題之一是過度獲取和獲取不足。 發生這種情況是因為客戶端下載數據的唯一方法是點擊返回固定數據結構的端點。 在這種情況下,過度獲取意味著客戶端下載的信息多於應用程序所需的信息。

另一方面,在 GraphQL 中,您只需向 GraphQL 服務器發送一個包含所需數據的查詢。 然後,服務器將使用您請求的確切數據的 JSON 對象進行響應——因此,不會過度獲取。 Sebastian Eschweiler 解釋了 RESTful API 和 GraphQL 之間的區別。

客戶端 GraphQL 是一個客戶端基礎設施,它與來自 GraphQL 服務器的數據交互以執行以下功能:

  • 它通過發送查詢和改變數據來管理數據,而無需您自己構建 HTTP 請求。 您可以花更少的時間來檢測數據,而將更多的時間用於構建實際的應用程序。
  • 它為您管理緩存的複雜性。 因此,您可以存儲和檢索從服務器獲取的數據,而無需任何第三方乾預,並且輕鬆避免重新獲取重複資源。 因此,它可以識別兩個資源何時相同,這對於復雜的應用程序來說非常有用。
  • 它使您的 UI 與 Optimistic UI 保持一致,Optimistic UI 是一種模擬突變結果(即創建的數據)並在接收到服務器響應之前更新 UI 的約定。 一旦從服務器接收到響應,樂觀的結果就會被丟棄並替換為實際結果。

有關客戶端 GraphQL 的更多信息,請花一個小時與 GraphQL 的共同創建者和 GraphQL Radio 上的其他酷人交流。

什麼是 Apollo 客戶端?

Apollo Client 是一個可互操作的、超靈活的、社區驅動的 GraphQL 客戶端,適用於 JavaScript 和原生平台。 其令人印象深刻的功能包括強大的狀態管理工具(Apollo Link)、零配置緩存系統、獲取數據的聲明式方法、易於實現的分頁以及客戶端應用程序的 Optimistic UI。

Apollo 客戶端不僅存儲從服務器獲取的數據的狀態,還存儲它在客戶端本地創建的狀態; 因此,它管理 API 數據和本地數據的狀態。

同樣重要的是要注意,您可以將 Apollo Client 與其他狀態管理工具(如 Redux)一起使用,而不會發生衝突。 另外,可以將您的狀態管理從 Redux 遷移到 Apollo Client(這超出了本文的範圍)。 最終,Apollo Client 的主要目的是使工程師能夠無縫地查詢 API 中的數據。

阿波羅客戶端的特點

Apollo Client 贏得了眾多工程師和公司的青睞,因為其非常有用的功能使構建現代強大的應用程序變得輕而易舉。 內置以下功能:

  • 緩存
    Apollo Client 支持動態緩存。
  • 樂觀的用戶界面
    Apollo Client 對 Optimistic UI 有很酷的支持。 它涉及在操作進行時臨時顯示操作的最終狀態(突變)。 一旦操作完成,真實數據將取代樂觀數據。
  • 分頁
    Apollo Client 具有內置功能,可以很容易地在應用程序中實現分頁。 它使用fetchMore函數解決了大多數技術難題,無論是在補丁中還是一次獲取數據列表,該函數帶有useQuery鉤子。

在本文中,我們將介紹這些功能的選擇。

理論夠了。 係好安全帶,拿杯咖啡來配煎餅,因為我們的手很髒。

構建我們的 Web 應用程序

這個項目的靈感來自 Scott Moss。

我們將構建一個簡單的寵物店網絡應用程序,其功能包括:

  • 從服務器端獲取我們的寵物;
  • 創建寵物(包括創建寵物的名稱、類型和圖像);
  • 使用 Optimistic UI;
  • 使用分頁來分割我們的數據。

首先,克隆存儲庫,確保starter分支是您克隆的內容。

入門

  • 為 Chrome 安裝 Apollo 客戶端開發工具擴展。
  • 使用命令行界面 (CLI),導航到克隆存儲庫的目錄,然後運行命令以獲取所有依賴項: npm install
  • 運行命令npm run app以啟動應用程序。
  • 仍在根文件夾中時,運行命令npm run server 。 這將為我們啟動我們的後端服務器,我們將在繼續進行時使用它。

該應用程序應在配置的端口中打開。 我的是https://localhost:1234/ ; 你的可能是別的東西。

如果一切正常,您的應用程序應如下所示:

克隆的起始分支 UI
克隆的起始分支 UI。 (大預覽)

您會注意到我們沒有可展示的寵物。 那是因為我們還沒有創建這樣的功能。

如果您已正確安裝 Apollo 客戶端開發工具,請打開開發工具並單擊托盤圖標。 你會看到“Apollo”和類似這樣的東西:

Apollo 客戶端開發工具
Apollo 客戶端開發工具。 (大預覽)

與 Redux 和 React 開發工具一樣,我們將使用 Apollo 客戶端開發工具來編寫和測試我們的查詢和突變。 該擴展隨 GraphQL Playground 一起提供。

取寵物

讓我們添加獲取寵物的功能。 轉到client/src/client.js 。 我們將編寫 Apollo 客戶端,將其鏈接到 API,將其導出為默認客戶端,並編寫新查詢。

複製以下代碼並將其粘貼到client.js中:

 import { ApolloClient } from 'apollo-client' import { InMemoryCache } from 'apollo-cache-inmemory' import { HttpLink } from 'apollo-link-http' const link = new HttpLink({ uri: 'https://localhost:4000/' }) const cache = new InMemoryCache() const client = new ApolloClient({ link, cache }) export default client

這是對上面發生的事情的解釋:

  • ApolloClient
    這將是包裝我們的應用程序的函數,因此,它與 HTTP 接口、緩存數據並更新 UI。
  • InMemoryCache
    這是 Apollo 客戶端中的規範化數據存儲,有助於在我們的應用程序中操作緩存。
  • HttpLink
    這是一個標準的網絡接口,用於修改 GraphQL 請求的控制流和獲取 GraphQL 結果。 它充當中間件,每次觸發鏈接時從 GraphQL 服務器獲取結果。 另外,它是其他選項的一個很好的替代品,比如Axioswindow.fetch
  • 我們聲明了一個分配給HttpLink實例的鏈接變量。 它需要一個uri屬性和一個值到我們的服務器,即https://localhost:4000/
  • 接下來是一個緩存變量,它保存InMemoryCache的新實例。
  • client 變量還接受ApolloClient的實例並包裝linkcache
  • 最後,我們導出client ,以便我們可以在整個應用程序中使用它。

在我們看到這一點之前,我們必須確保我們的整個應用程序都暴露給 Apollo,並且我們的應用程序可以接收從服務器獲取的數據並且它可以改變這些數據。

為此,讓我們轉到client/src/index.js

 import React from 'react' import ReactDOM from 'react-dom' import { BrowserRouter } from 'react-router-dom' import { ApolloProvider } from '@apollo/react-hooks' import App from './components/App' import client from './client' import './index.css' const Root = () => ( <BrowserRouter>
 <ApolloProvider client={client}> <App /> </ApolloProvider>
 </BrowserRouter> ); ReactDOM.render(<Root />, document.getElementById('app')) if (module.hot) { module.hot.accept() }

正如您將在突出顯示的代碼中註意到的那樣,我們將App組件包裝在ApolloProvider中,並將客戶端作為道具傳遞給clientApolloProvider類似於 React 的Context.Provider 。 它包裝您的 React 應用程序並將客戶端放置在上下文中,這允許您從組件樹中的任何位置訪問它。

要從服務器獲取我們的寵物,我們需要編寫查詢來請求我們想要的確切字段。 前往client/src/pages/Pets.js ,然後將以下代碼複製並粘貼到其中:

 import React, {useState} from 'react' import gql from 'graphql-tag' import { useQuery, useMutation } from '@apollo/react-hooks' import PetsList from '../components/PetsList' import NewPetModal from '../components/NewPetModal' import Loader from '../components/Loader'

const GET_PETS = gql` query getPets { pets { id name type img } } `;

export default function Pets () { const [modal, setModal] = useState(false)
 const { loading, error, data } = useQuery(GET_PETS); if (loading) return <Loader />; if (error) return <p>An error occured!</p>;


 const onSubmit = input => { setModal(false) } if (modal) { return <NewPetModal onSubmit={onSubmit} onCancel={() => setModal(false)} /> } return ( <div className="page pets-page"> <section> <div className="row betwee-xs middle-xs"> <div className="col-xs-10"> <h1>Pets</h1> </div> <div className="col-xs-2"> <button onClick={() => setModal(true)}>new pet</button> </div> </div> </section> <section>
 <PetsList pets={data.pets}/>
 </section> </div> ) }

使用一些代碼,我們就可以從服務器獲取寵物。

什麼是gql?

需要注意的是,GraphQL 中的操作通常是用graphql-tag和反引號編寫的 JSON 對象。

gql標籤是 JavaScript 模板文字標籤,可將 GraphQL 查詢字符串解析為 GraphQL AST(抽象語法樹)。

  • 查詢操作
    為了從服務器獲取我們的寵物,我們需要執行一個查詢操作。
    • 因為我們正在進行query操作,所以我們需要在命名之前指定操作的type
    • 我們的查詢名稱是GET_PETS 。 使用 camelCase 作為字段名稱是 GraphQL 的命名約定。
    • 我們的字段名稱是pets 。 因此,我們從服務器中指定了我們需要的確切字段(id, name, type, img)
    • useQuery是一個 React 鉤子,它是在 Apollo 應用程序中執行查詢的基礎。 為了在我們的 React 組件中執行查詢操作,我們調用了useQuery鉤子,它最初是從@apollo/react-hooks導入的。 接下來,我們向它傳遞一個 GraphQL 查詢字符串,在我們的例子中是GET_PETS
  • 當我們的組件渲染時, useQuery從 Apollo 客戶端返回一個對象響應,其中包含加載、錯誤和數據屬性。 因此,它們被解構,以便我們可以使用它們來呈現 UI。
  • useQuery很棒。 我們不必包含async-await 。 它已經在後台處理好了。 很酷,不是嗎?
    • loading
      這個屬性幫助我們處理應用程序的加載狀態。 在我們的例子中,我們在應用程序加載時返回一個Loader組件。 默認情況下,加載是false
    • error
      以防萬一,我們使用此屬性來處理可能發生的任何錯誤。
    • data
      這包含來自服務器的實際數據。
    • 最後,在我們的PetsList組件中,我們傳遞了pets道具,其中data.pets作為對象值。

至此,我們已經成功查詢到了我們的服務器。

要啟動我們的應用程序,讓我們運行以下命令:

  • 啟動客戶端應用程序。 在 CLI 中運行命令npm run app
  • 啟動服務器。 在另一個 CLI 中運行命令npm run server
VScode CLI 分區以啟動客戶端和服務器。
VScode CLI 分區以啟動客戶端和服務器。 (大預覽)

如果一切順利,您應該會看到:

從服務器查詢的寵物。
從服務器查詢的寵物。

變異數據

在 Apollo Client 中變異數據或創建數據與查詢數據幾乎相同,只有非常細微的變化。

仍然在client/src/pages/Pets.js中,讓我們複製並粘貼突出顯示的代碼:

 .... const GET_PETS = gql` query getPets { pets { id name type img } } `;

const NEW_PETS = gql` mutation CreateAPet($newPet: NewPetInput!) { addPet(input: $newPet) { id name type img } } `;

 const Pets = () => { const [modal, setModal] = useState(false) const { loading, error, data } = useQuery(GET_PETS);
 const [createPet, newPet] = useMutation(NEW_PETS);
 const onSubmit = input => { setModal(false)
 createPet({ variables: { newPet: input } }); } if (loading || newPet.loading) return <Loader />; if (error || newPet.error) return <p>An error occured</p>;
  
 if (modal) { return <NewPetModal onSubmit={onSubmit} onCancel={() => setModal(false)} /> } return ( <div className="page pets-page"> <section> <div className="row betwee-xs middle-xs"> <div className="col-xs-10"> <h1>Pets</h1> </div> <div className="col-xs-2"> <button onClick={() => setModal(true)}>new pet</button> </div> </div> </section> <section> <PetsList pets={data.pets}/> </section> </div> ) } export default Pets

要創建突變,我們將採取以下步驟。

1. mutation

要創建、更新或刪除,我們需要執行mutation操作。 mutation操作有一個CreateAPet名稱,帶有一個參數。 這個參數有一個$newPet變量,類型為NewPetInput! 表示需要操作; 因此,除非我們傳遞一個類型為NewPetInputnewPet變量,否則 GraphQL 不會執行該操作。

2. addPet

addPet函數位於mutation操作內部,接受一個input參數並設置為我們的$newPet變量。 addPet函數中指定的字段集必須與查詢中的字段集相同。 我們操作中的字段集是:

  • id
  • name
  • type
  • img

3. useMutation

useMutation React 鉤子是在 Apollo 應用程序中執行突變的主要 API。 當我們需要改變數據時,我們在 React 組件中調用useMutation它傳遞一個 GraphQL 字符串(在我們的例子中是NEW_PETS )。

當我們的組件渲染useMutation時,它會在一個數組中返回一個元組(即構成記錄的有序數據集),其中包括:

  • 一個mutate函數,我們可以隨時調用它來執行變異;
  • 具有表示突變執行當前狀態的字段的對象。

useMutation鉤子傳遞了一個 GraphQL 突變字符串(在我們的例子中是NEW_PETS )。 我們解構了元組,它是一個函數( createPet ),它將改變數據和對象字段( newPets )。

4. createPet

在我們的onSubmit函數中,在setModal狀態之後不久,我們定義了我們的createPet 。 該函數接受一個variable ,其對象屬性的值設置為{ newPet: input }input表示我們表單中的各種輸入字段(例如名稱、類型等)。

完成後,結果應如下所示:

沒有即時更新的突變
沒有即時更新的突變。

如果您仔細觀察 GIF,您會注意到我們創建的寵物不會立即出現,只有在頁面刷新時才會出現。 但是,它已在服務器上更新。

最大的問題是,為什麼我們的寵物不立即更新? 讓我們在下一節中找出答案。

在 Apollo 客戶端中緩存

我們的應用沒有自動更新的原因是我們新創建的數據與 Apollo Client 中的緩存數據不匹配。 因此,對於需要從緩存中更新的確切內容存在衝突。

簡而言之,如果我們執行更新或刪除多個條目(一個節點)的突變,那麼我們負責更新引用該節點的任何查詢,以便它修改我們的緩存數據以匹配突變對我們的後台所做的修改-結束數據。

保持緩存同步

每次執行突變操作時,有幾種方法可以使我們的緩存保持同步。

第一種是在突變後重新獲取匹配的查詢,使用refetchQueries對象屬性(最簡單的方法)。

注意:如果我們要使用這個方法,它將在我們的createPet函數中獲取一個名為refetchQueries的對象屬性,並且它將包含一個具有查詢值的對像數組: refetchQueries: [{ query: GET_PETS }]

因為我們在本節中的重點不僅僅是在 UI 中更新我們創建的寵物,而是為了操作緩存,我們不會使用這種方法。

第二種方法是使用update功能。 在 Apollo 客戶端中,有一個update助手函數可以幫助修改緩存數據,以便它與突變對我們的後端數據所做的修改同步。 使用這個函數,我們可以讀寫緩存。

更新緩存

複製以下突出顯示的代碼,並將其粘貼到client/src/pages/Pets.js

 ...... const Pets = () => { const [modal, setModal] = useState(false) const { loading, error, data } = useQuery(GET_PETS);
 const [createPet, newPet] = useMutation(NEW_PETS, { update(cache, { data: { addPet } }) { const data = cache.readQuery({ query: GET_PETS }); cache.writeQuery({ query: GET_PETS, data: { pets: [addPet, ...data.pets] }, }); }, } );
 .....

update函數接收兩個參數:

  • 第一個參數是來自 Apollo 客戶端的緩存。
  • 第二個是來自服務器的確切突變響應。 我們解構data屬性並將其設置為我們的突變( addPet )。

接下來,要更新函數,我們需要檢查需要更新的查詢(在我們的例子中是GET_PETS查詢)並讀取緩存。

其次,我們需要寫入已讀取的query ,以便它知道我們將要更新它。 我們通過傳遞一個包含query對象屬性的對象來做到這一點,該屬性的值設置為我們的query操作( GET_PETS ),以及一個data屬性,其值是一個pet對象,它具有一個addPet突變的數組和一個副本寵物的數據。

如果您仔細按照這些步驟操作,您應該會看到您的寵物在創建時自動更新。 讓我們來看看變化:

寵物即時更新
寵物即時更新。

樂觀的用戶界面

很多人都是裝載機和旋轉機的忠實粉絲。 使用裝載機沒有任何問題; 在某些完美的用例中,加載器是最佳選擇。 我寫過關於加載器與微調器及其最佳用例的文章。

Loaders 和 spinners 確實在 UI 和 UX 設計中扮演著重要的角色,但是 Optimistic UI 的到來已經搶了風頭。

什麼是樂觀 UI?

Optimistic UI 是一種約定,它模擬突變(創建的數據)的結果並在接收到來自服務器的響應之前更新 UI。 一旦從服務器接收到響應,樂觀的結果就會被丟棄並替換為實際結果。

最後,樂觀的 UI 只不過是一種管理感知性能和避免加載狀態的方法。

Apollo Client 有一種非常有趣的方式來集成 Optimistic UI。 它為我們提供了一個簡單的鉤子,允許我們在突變後寫入本地緩存。 讓我們看看它是如何工作的!

第1步

轉到client/src/client.js ,只添加突出顯示的代碼。

 import { ApolloClient } from 'apollo-client' import { InMemoryCache } from 'apollo-cache-inmemory' import { HttpLink } from 'apollo-link-http'
import { setContext } from 'apollo-link-context' import { ApolloLink } from 'apollo-link' const http = new HttpLink({ uri: "https://localhost:4000/" }); const delay = setContext( request => new Promise((success, fail) => { setTimeout(() => { success() }, 800) }) ) const link = ApolloLink.from([ delay, http ])
const cache = new InMemoryCache() const client = new ApolloClient({ link, cache }) export default client

第一步涉及以下內容:

  • 我們從apollo-link-context導入setContextsetContext函數接受一個回調函數並返回一個其setTimeout設置為800ms的promise,以便在執行突變操作時創建一個延遲。
  • ApolloLink.from方法確保代表來自HTTP的鏈接(我們的 API)的網絡活動被延遲。

第2步

下一步是使用 Optimistic UI 掛鉤。 滑回client/src/pages/Pets.js ,只添加下面突出顯示的代碼。

 ..... const Pets = () => { const [modal, setModal] = useState(false) const { loading, error, data } = useQuery(GET_PETS); const [createPet, newPet] = useMutation(NEW_PETS, { update(cache, { data: { addPet } }) { const data = cache.readQuery({ query: GET_PETS }); cache.writeQuery({ query: GET_PETS, data: { pets: [addPet, ...data.pets] }, }); }, } ); const onSubmit = input => { setModal(false) createPet({ variables: { newPet: input },
 optimisticResponse: { __typename: 'Mutation', addPet: { __typename: 'Pet', id: Math.floor(Math.random() * 10000 + ''), name: input.name, type: input.type, img: 'https://via.placeholder.com/200' } }
 }); } .....

如果我們希望 UI 在創建寵物時立即更新,而不是等待服務器響應,則使用optimisticResponse響應對象。

上面的代碼片段包括以下內容:

  • __typename由 Apollo 注入到查詢中以獲取查詢實體的type 。 Apollo 客戶端使用這些類型來構建id屬性(這是一個符號),用於apollo-cache中的緩存目的。 因此, __typename是查詢響應的有效屬性。
  • 突變被設置為optimisticResponse__typename
  • 正如前面定義的那樣,我們的變異名稱是addPet ,而__typenamePet
  • 接下來是我們希望樂觀響應更新的突變字段:
    • id
      因為我們不知道來自服務器的 ID 是什麼,所以我們使用Math.floor製作了一個。
    • name
      此值設置為input.name
    • type
      類型的值為input.type
    • img
      現在,因為我們的服務器為我們生成圖像,所以我們使用佔位符來模仿來自服務器的圖像。

這確實是一段漫長的旅程。 如果你到了最後,不要猶豫,從椅子上休息一下,喝杯咖啡。

讓我們看看我們的結果。 該項目的支持存儲庫位於 GitHub 上。 克隆並試驗它。

寵物店應用程序的最終結果
我們應用程序的最終結果。

結論

Apollo Client 的驚人功能,例如 Optimistic UI 和分頁,使構建客戶端應用程序成為現實。

雖然 Apollo Client 可以很好地與其他框架(例如 Vue.js 和 Angular)配合使用,但 React 開發人員擁有 Apollo Client Hooks,因此他們情不自禁地喜歡構建出色的應用程序。

在本文中,我們只觸及了表面。 掌握 Apollo Client 需要不斷練習。 因此,繼續克隆存儲庫,添加分頁,並使用它提供的其他功能。

請在下面的評論部分分享您的反饋和經驗。 我們還可以在 Twitter 上討論您的進展。 乾杯!

參考

  • “React 中的客戶端 GraphQL”,Scott Moss,前端大師
  • “文檔”,Apollo 客戶端
  • “使用 React 的樂觀 UI”,Patryk Andrzejewski
  • “樂觀用戶界面的真實謊言”,Smashing Magazine