graphql-codegenで生成した関数でクエリを実行する時には,リクエスト完了を待ちましょうという反省
こんにちは。kazです。フロントエンドのエンジニアとかをやっています。
10秒でわかる記事の内容
ReactとGraphQLを用いて,書籍のISBNから対応した書籍情報を取得するページを作成しようとしていました。
graphql-code-generatorを用いて書籍情報を取得する関数を生成し実行したところ,TypeError: Cannot read property 'book' of undefined
というエラーが表示されてしまいました。
原因としては,データの取得リクエスト完了を待たずにレスポンスデータを参照しようとしていたことが原因でした。
起きたこと
今回,私はNext.js + TypeScript + Apollo Client環境で書籍情報を取得するページを作成していました。
書籍情報を取得するためのスキーマは次のように定義しました。ISBNを指定すると,そのISBNに対応した書籍のタイトルを取得するものになります。
query book($isbn: ID!) {
book(isbn: $isbn) {
isbn
title
}
}
このようなスキーマから型定義や,クエリを実行してデータを取得する関数を生成することができるgraphql-codegen
+ [@graphql-codegen/typescript-react-apollo](https://graphql-code-generator.com/docs/plugins/typescript-react-apollo)
というライブラリがあります。
今回は先ほどのスキーマからuseBookQuery
関数を自動生成しました。
こちらのuseBookQuery
関数を利用し,ISBNから取得した書籍タイトルを表示する箇所をReactで次ように実装しました。
import { useBookQuery } from "../../../@types/codegen/graphql";
...
const { data } = useBookQuery({
variables: {
isbn: isbn,
},
});
return (
<div>
<h1>Book</h1>
{data && data.book && (
<div>
{data.book.title}
</div>
)}
</div>
);
};
しかしコンソールには次のようなエラーが出力され,取得できるはずのデータを表示することができませんでした。
TypeError: Cannot read property 'book' of undefined
...
解決した方法
エラーとなっていた原因は,データの取得が完了する前にデータを参照しようとしていたからでした。
useBookQuery
関数は,レスポンスデータだけでなく,リクエストが処理中であるかどうかを示すloading
やエラーの発生を示すerror
を受け取ることができます。
これを利用し,データの取得が終わっていないloading = true
状態の時などはdata
を参照しようとせず,取得が完了して初めてdata
に触るように変更することで,無事に書籍の情報を取得し画面上へ表示することができました。
import { useBookQuery } from "../../../@types/codegen/graphql";
...
const { data, loading, error } = useBookQuery({
variables: {
isbn: isbn,
},
});
if (loading) return <p>Loading...</p>;
if (error) return <p>ERROR: {error.message}</p>;
if (!data) return <p>Not found</p>;
return (
<Fragment>
<h1>Book</h1>
{data && data.book && (
<div>
{data.book.title}
</div>
)}
</Fragment>
);
};
ということで自分のメモ的な感じではありますが、何かの参考になれば幸いです。
書籍情報を取得するためにopenBDが提供するAPIを利用させていただきました。
Discussion