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
