本系列文以製作專案為主軸,紀錄小弟學習React以及GrahQL的過程。主要是記下重點步驟以及我覺得需要記憶的部分,有覺得不明確的地方還請留言多多指教。
後端API建立好了,現在回到前端來發送請求取得資料。
Apollo 針對前端也有工具,Apollo client,可以在發送GraphQL請求後建立前端cache,在前端發送重複請求時直接從快取存取資料,降低向Server請求的頻率。
這個Cache其實就如同Redux的Store,所以除了向Server請求資料外,Apollo Client也能用於前端狀態管理,好處在於可以用GraphQL的方式存取local state,靈活性高。
目前的 Apollo 版本沒有跟Redux的store集成的方法,只能各管各的,或是直接取代Redux 用 Apollo 做 local state的管理,不過這邊只是學習筆記,就不弄大工程取代掉Redux,簡單示範如何用 Apollo Client 進行 GraphQL 請求。
回到 client資料夾,用 npm 安裝套件:
npm install @apollo/client graphql
在 index.js 中建立 Apollo client 實例:
//index.js
//...
import { ApolloClient, InMemoryCache } from "@apollo/client";
const client = new ApolloClient({
uri: "http://localhost:4000/", //指定API網址
cache: new InMemoryCache(), //建立 cache
});
//...
然後將 client 應用給 APP:
//index.js
//...
import { ApolloProvider } from "@apollo/client";
//...
ReactDOM.render(
<React.StrictMode>
<ApolloProvider client={client}> //將APP包裝
<Provider store={store}> //這是原本的Redux Store
<App />
</Provider>
</ApolloProvider>
</React.StrictMode>,
document.getElementById("root")
);
這樣發送 GraphQL 請求的準備就完成了。
Apollo Client 在2.6版後改以 hook 的方式進行 query 跟 mutation。而要進行請求,要先撰寫graphQL 請求字串,在提供給hook 使用。
以query lists為例,先將 useQuery 跟 gql 標籤引入KanBan:
//KanBan.jsx
import { useQuery, gql } from "@apollo/client";
const GET_LISTS = gql`
query GetLists {
lists {
id
title
todos {
id
name
}
}
}
`;
注意必須要以 gql 標籤將字串轉為請求物件。
接著就能在元件中以 useQuery 發送請求取得資料
//KanBan.jsx
export default function KanBan({ lists, editState, kanBanMenuState }) {
const { loading, error, data } = useQuery(GET_LISTS);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
console.log(data.lists);
//...
}
useQuery的回傳值中有一些請求的進行狀態,像是loading為true時表示請求還在處理中,就可以利用這個布林值先渲染載入畫面。
而當請求完成後就能從data取得資料用於元件渲染,或是error取得錯誤訊息。
跟 useQuery 一樣可以用 useMutation 進行 mutation 請求,順便示範如何在請求中帶入參數。
一樣先引入 fucntion 後用 gql 編寫請求:
//List.jsx
import { gql, useMutation } from "@apollo/client";
const ADD_TODO = gql`
mutation AddTodo($name: String!, $listId: Int!) {
addTodo(name: $name, listId: $listId) {
id
name
}
}
`;
注意宣告 AddTodo 時宣告了參數與其型別,然後其中的請求時再以這些參數帶入請求。
將ADD_TODO用於 mutation:
const List = React.forwardRef(...)=> {
const [addTodo] = useMutation(ADD_TODO);
//...
}
useMutation 回傳值第一個是執行請求的function,可以在click時呼叫:
//NewTodo.jsx
//...
function handleAddTodo(e) {
if (e.target.value.trim()) {
addTodo({ variables: { listId: listId, name: e.target.value } });
}
e.target.value = "";
toggleShowNew();
}
//...
要提供物件作為參數給addTodo,並以 variables 宣告帶入請求的參數。
成功執行 mutation 後應該會發現頁面並沒有相應的變化,因為 mutatoin 修改完 Server、資料庫的訊息後本地端的cache並不一定會自動更新,可以重新發送query請求不過那太耗資源了,應該要在mutation後利用回傳的訊息編輯cache。
編輯 cache 還挺複雜的,就分篇吧。