Apollo ClientはReactで使える状態管理ライブラリです。ローカルとリモートのデータをGraphQLで扱えます。本稿でつくるのは、Apollo Client公式の「Get started with Apollo Client」で紹介されている作例です。ただし、TypeScriptを採り入れ、アプリケーションは簡単にモジュール分けしました。
Apollo Clientアプリケーションをつくる準備
Reactアプリケーションのひな形は、Create React Appでつくることにします。オプションとして--template typescript
を加えれば、TypeScriptの環境が簡単に加わえられて便利です(「Create React AppでTypeScriptが加わったひな形アプリケーションをつくる」参照)。
では、Apollo Clientをインストールしましょう。GraphQLも、依存があるのでインストールに加えてください(クエリを使わなくても必要です)。
npm install @apollo/client graphql
ApolloClient
を初期化する
まず、ApolloClient
のインスタンスをつくります。コンストラクタに渡すのはオプションオブジェクトで、ふたつの設定を加えました。uri
はGraphQLサーバーのURLの文字列です。cache
はApollo Clientが読み込んだクエリ結果の保存先として必須で、多くの場合InMemoryCache
インスタンスが定められます。
-
uri: string
- Apollo Clientが通信するGraphQLのエンドポイントURI。 -
cache: ApolloCache
- クエリの結果をローカルに保存するためにApollo Clientが用いるべきキャッシュ(必須)。@apollo/client
パッケージの提供するInMemoryCache
が推奨。
Reactのページへのデータの差し込みはあとにして、クエリを送ってみましょう(コード001)。ApolloClient
インスタンスに対して呼び出すのはquery()
メソッドです。引数には、gql
テンプレートリテラルで包んだ、クエリ文字列を渡してください。
コード001■ApolloClient
でクエリを送る
import { useEffect } from 'react';
import {
ApolloClient,
InMemoryCache,
gql,
} from '@apollo/client';
const client = new ApolloClient({
uri: 'https://48p1r2roz4.sse.codesandbox.io',
cache: new InMemoryCache(),
});
function App() {
useEffect(() => {
client
.query({
query: gql`
query GetRates {
rates(currency: "USD") {
currency
}
}
`,
})
.then((result) => console.log(result));
}, []);
return (
<div>
<h1>Apollo Client</h1>
</div>
);
}
export default App;
コードを実行すると、コンソールにクエリ結果のオブジェクトが示されるはずです(図001)。動きは、CodeSandboxに公開した以下のサンプル001でお確かめください1。
図001■コンソールに出力されたクエリの結果
サンプル001■React + TypeScript: Using GraphQL queries with Apollo Client 01
ApolloProvider
でReactのコンテクストにつなぐ
ApolloProvider
コンポーネントを使うと、Apollo ClientをReactのコンテクストにつなげられます。仕組みはReactのContext.Provider
と同じです。包まれたツリーの中のどのコンポーネントからでも、Apollo Clientのデータにアクセスできます。GraphQLのデータを用いる大もとのコンポーネントをApolloProvider
に含めてください。プロパティclient
に与えるのは、ApolloClient
インスタンスです。
// import { useEffect } from 'react';
// import { ApolloClient, InMemoryCache, gql } from '@apollo/client';
import {
ApolloProvider,
} from '@apollo/client';
function App() {
/* useEffect(() => {
}, []); */
return (
<ApolloProvider client={client}>
<div>
</div>
</ApolloProvider>
);
}
useQuery
フックでデータを読み込む
ApolloProvider
でReactのコンテクストにつなげたら、データをクエリで要求してページに読み込めます。用いるフックがuseQuery
です。GraphQLのデータをReactと共有します。クエリは、ルートモジュール(src/App.tsx
)に変数(ExchangeRates
)で定めておきましょう。求めるプロパティとして、通貨(currency
)のほかに為替レート(rate
)を加えました。このあと定める子コンポーネント(ExchangeRates
)のプロパティ(exchangeRates
)にクエリを加えます。
import { ExchangeRates } from './ExchangeRates';
const EXCHANGE_RATES = gql`
query GetExchangeRates {
rates(currency: "USD") {
currency
rate
}
}
`;
function App() {
return (
<ApolloProvider client={client}>
<div>
<ExchangeRates exchangeRates={EXCHANGE_RATES} />
</div>
</ApolloProvider>
);
}
useQuery
フックに渡したクエリ(DocumentNode
型)は、コンポーネントが描画されるたびに実行され、返されるのは新たな結果のオブジェクトです。為替レートを表示する子のモジュール(src/ExchangeRates.tsx
)は、3つのプロパティを取り出しています(コード002)。
-
loading: boolean
- ロード中かどうかのブール値。true
のときは、まだクエリの結果が返されていない。 -
error: ApolloError
- クエリにエラーが起こったことを示すオブジェクト。 -
data: TData
- GraphQLクエリが正しく実行されたときに得られる結果のデータ。
コードを実行すると、少しの間「Loading...」のテキストが示され、そのあと為替レートの一覧が表示されるでしょう。クエリの状態に応じて、コンポーネントがリアクティブに再描画されているということです。書き改めたルートモジュール(src/App.tsx
)のコードも併せてまとめておきました。動きはCodeSandboxに公開した以下のサンプル002でお確かめください。
コード002■useQueryフックで読み込んだデータをページに表示する。
import { VFC } from 'react';
import {
DocumentNode,
useQuery,
} from '@apollo/client';
type Props = {
exchangeRates: DocumentNode;
};
export const ExchangeRates: VFC<Props> = ({ exchangeRates }) => {
const { loading, error, data } = useQuery(exchangeRates);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
return data.rates.map(
({ currency, rate }: { currency: string; rate: string }) => (
<div key={currency}>
<p>
{currency}: {rate}
</p>
</div>
)
);
};
import {
ApolloClient,
ApolloProvider,
InMemoryCache,
gql
} from '@apollo/client';
import { ExchangeRates } from './ExchangeRates';
const client = new ApolloClient({
uri: 'https://48p1r2roz4.sse.codesandbox.io',
cache: new InMemoryCache(),
});
const EXCHANGE_RATES = gql`
query GetExchangeRates {
rates(currency: "USD") {
currency
rate
}
}
`;
function App() {
return (
<ApolloProvider client={client}>
<div>
<h1>Apollo Client</h1>
<ExchangeRates exchangeRates={EXCHANGE_RATES} />
</div>
</ApolloProvider>
);
}
export default App;
サンプル002■React + TypeScript: Using GraphQL queries with Apollo Client 02