graphql-codegenで生成した関数でクエリを実行する時には,リクエスト完了を待ちましょうという反省

2 min読了の目安(約2200字TECH技術記事

こんにちは。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を利用させていただきました。