目錄
Apollo client是甚麼
Apollo client是一個狀態管理用的package,常用於前端為React,後端為GraphQL的專案
透過它可以和本地、遠端的GraphQL API互動
前一篇提到的GraphQL cache問題也可以透過它處理
基本使用
- 安裝 - npm i @apollo/client // 用於解析GraphQL的query npm i graphql
- 初始化Apollo client - // ApolloClient用於建立連線 // InMemoryCache用於快取住fetch下來的資料 // ApolloProvider是用於包裹React app的組件 // gql是一個函式,參數是query string import { ApolloClient, InMemoryCache, ApolloProvider, gql } from '@apollo/client'; // 建立連線 const client = new ApolloClient({ // API網址,又稱作endpoint uri: 'https://flyby-gateway.herokuapp.com/', cache: new InMemoryCache(), });
- query - client.query({ query:gql`{ locations { photo name } }` }).then(d => console.log(d)); // 或者打開dev tool的Network就能看到playload看response // response會有撈出來的資料
- 把client用到React - 使用ApolloProvider組件,可以連接Apollo client和React,其功能類似React的Context.Provider - 使用ApolloProvider後它會取代context,在它底下的組件都可以連到Apollo client,因此官方推薦把它放在index.js - // index.js import React from 'react'; import ReactDOM from 'react-dom/client'; import './style/index.css'; import App from './App'; import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client'; const client = new ApolloClient({ uri: 'https://flyby-gateway.herokuapp.com/', // API網址 cache: new InMemoryCache(), }); const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <ApolloProvider client={client}> <App /> </ApolloProvider> );
- 使用useQuery撈資料 - useQuery是一個React hook,它會回傳loading、error狀態、data - 也可以設定onCompelete、onError時呼叫哪個方法、做什麼 - Apollo client撈到資料後會自動把它- 快取住,這樣下次撈同樣的資料時就會- 更快 - // ApolloTimeline.js import { useQuery, gql } from '@apollo/client'; export default function ApolloTimeline(props){ const { loading, error, data } = useQuery(gql` { histories(sort: "event_date_utc") { event_date_utc title details flight { launch_success } } } `); if (loading) return <p>loading...</p>; if (error) return <p>Error :(</p>; return ( <div> <Timeline position="alternate"> { data.histories.map((i, index) => ( <TimelineItem key={index}> <TimelineOppositeContent> {timeFormatter(i.event_date_utc)}</TimelineOppositeContent> <TimelineSeparator> <TimelineDot color="secondary" /> {index === data.histories.length - 1? null : <TimelineConnector />} </TimelineSeparator> <TimelineContent> <Chip label={i.title} color={i.flight?.launch_success? 'success' : 'default'}></Chip> </TimelineContent> </TimelineItem> )) } </Timeline> </div> ) }
refetch & variable
refetch常用於根據使用者的動作撈資料的情況,例如切換分頁時

// ApolloRefetch.js
import { useQuery, gql } from '@apollo/client';
import Chip from '@mui/material/Chip';
import Paper from '@mui/material/Paper';
import CircularProgress from '@mui/material/CircularProgress';
function timeFormatter(str){
  if(!str) return '';
  return str.replace(/T|Z/g, ' ');
}
export default function ApolloRefetch(props){
  const queryMultiple = () => {
    // eslint-disable-next-line react-hooks/rules-of-hooks
    const res1 = useQuery(gql`
    query historyId{
      histories{
        id
      }
    }
  `);
    // eslint-disable-next-line react-hooks/rules-of-hooks
    const res2 = useQuery(gql`
    query history($id:ID!){
      history(id:$id){
        details
        event_date_utc
        flight {
          launch_success
          mission_name
        }
        title
        id
      }
    }
    `, {variables:{id:'1'}});
    return [res1, res2];
  };
  const [
      { loading: isIdLoading, error: isIdError, data: idData },
      { loading, data, refetch }
  ] = queryMultiple();
  if (isIdLoading) return <p>loading...</p>;
  if (isIdError) return <p>Error :(</p>;
  return (
    <div className='h-screen p-2'>
        <div className='flex justify-around'>
          {
              idData?.histories?.map((i, index) => <Chip key={index} 
                                                        color={data.history?.id === i.id? 'info' : 'default'} 
                                                        label={i.id} 
                                                        onClick={() => refetch({id:i.id})}></Chip>)
          }
        </div>
        <Paper elevation={3} sx={{padding:4, margin:4, display:'flex', flexDirection:'column', justifyContent:'center', alignItems:'center'}}>
          {
            loading? <CircularProgress/> : <>
                                            <h1 className='text-xl bold border-b-4 border-double border-zinc-600 mb-4 pb-1'>{data.history?.title}</h1>
                                            <p className='mb-2'>{timeFormatter(data.history?.event_date_utc)}</p>
                                            <p className='mb-2'>{data.history?.details}</p>
                                            <p className='mb-2'>{data.history?.flight?.mission_name}</p>
                                            <p>{data.history?.flight?.launch_success}</p>
                                          </>
          }
        </Paper>
    </div>
  )
}
參考資料
Get started with Apollo Client
Apollo client - Queries
Refetching queries in Apollo Client
Cleaning Unwanted Fields From GraphQL Responses
playground


