ReactのカスタムフックでGraphQL APIを扱う方法!初心者でもわかる実践入門
生徒
「先生、REST APIはよく聞きますけど、GraphQL APIって何なんですか?」
先生
「GraphQL APIは、欲しいデータだけをリクエストできる新しい仕組みです。必要な情報をピンポイントで取れるので効率が良いんです。」
生徒
「なるほど!じゃあReactでそのGraphQL APIを使うにはどうすればいいんですか?」
先生
「カスタムフックを作ると便利です。データ取得やエラーハンドリングをまとめることで、シンプルに使えるようになりますよ。」
1. GraphQL APIとは?
GraphQL APIとは、Facebookが開発したデータ取得のための仕組みです。通常のREST APIでは、サーバーから決められたデータが返ってきますが、GraphQLでは欲しい項目だけを指定してリクエストできます。
例えば、ショッピングサイトで「商品名だけが欲しい」と思ったときにREST APIだと価格や説明もまとめて送られてきます。しかしGraphQLでは「商品名だけ」と書けば、それだけを返してくれるのです。まるでレストランで「サラダだけください」と注文するイメージです。
2. GraphQLの基本的な使い方
GraphQLでは「クエリ」という書き方でデータを指定します。例えば次のように書くと、ユーザーの名前とメールアドレスだけを取得できます。
{
user {
name
email
}
}
このように、欲しいデータを明確に指定できるのがGraphQLの特徴です。
3. ReactでGraphQL APIを呼び出すには?
ReactでGraphQL APIを使うには、まずfetch関数を利用してサーバーにリクエストを送ります。そのとき、GraphQLのクエリを文字列として送るのがポイントです。
const fetchGraphQL = async (query) => {
const response = await fetch("https://example.com/graphql", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query }),
});
return response.json();
};
この関数を使えば、好きなクエリをサーバーに送ることができます。
4. カスタムフックを作ってGraphQLを扱う
毎回同じように書くのは大変なので、カスタムフックを作って共通化しましょう。カスタムフックはReactの再利用できる関数で、データ取得や状態管理を簡単にまとめられます。
import { useState, useEffect } from "react";
function useGraphQL(query) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch("https://example.com/graphql", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query }),
});
const result = await response.json();
setData(result.data);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
fetchData();
}, [query]);
return { data, loading, error };
}
export default useGraphQL;
5. カスタムフックを使ってデータを取得する
作ったフックを実際に使ってみましょう。例えば「ユーザー名とメールアドレス」を取得するクエリを実行してみます。
import React from "react";
import useGraphQL from "./useGraphQL";
function App() {
const query = `
{
user {
name
email
}
}
`;
const { data, loading, error } = useGraphQL(query);
if (loading) return <p>読み込み中...</p>;
if (error) return <p>エラーが発生しました</p>;
return (
<div>
<h1>ユーザー情報</h1>
<p>名前: {data.user.name}</p>
<p>メール: {data.user.email}</p>
</div>
);
}
export default App;
6. カスタムフックでGraphQLを扱うメリット
GraphQL APIをカスタムフックでまとめることで、次のようなメリットがあります。
- データ取得処理を何度も書かずに済む
- エラーや読み込み状態の管理を自動化できる
- 複数の画面で簡単に再利用できる
特に複雑なアプリでは「どの画面でも同じように使える」ことがとても重要です。
7. 応用:変数付きのGraphQLクエリ
GraphQLでは変数を使って柔軟にリクエストできます。例えば「ユーザーIDを指定して情報を取得」するような場面です。これもカスタムフックで簡単に対応できます。
このように、GraphQLとReactのカスタムフックを組み合わせると、効率的で使いやすいAPI管理が可能になります。
まとめ
ここまでReactとGraphQLを組み合わせた、効率的なデータ取得の方法について解説してきました。Reactの開発現場において、GraphQLはその柔軟性と効率性の高さから、非常に多くのプロジェクトで採用されています。特に、今回ご紹介した「カスタムフック」を利用した実装パターンは、保守性の高いコードを書くための基本中の基本とも言える手法です。
GraphQLの最大の利点は、クライアント側が必要なデータの構造を決定できる点にあります。従来のREST APIでは、エンドポイントごとに返ってくるデータが決まっており、フロントエンド側で不要なデータまで受け取ってしまう「オーバーフェッチ」や、逆に必要なデータが足りずに何度もリクエストを送る「アンダーフェッチ」といった問題が頻繁に発生していました。GraphQLは、単一のエンドポイントに対してクエリを送信するだけで、これらすべての問題を一気に解決してくれます。
カスタムフックによるロジックの共通化
Reactのカスタムフック(Custom Hooks)を活用することで、useStateやuseEffectを用いた非同期処理のロジックを、コンポーネントから完全に切り離すことができます。これにより、UIを担当するコンポーネントは「データをどう表示するか」だけに集中でき、コードの可読性が飛躍的に向上します。また、一度作成したuseGraphQLのようなフックは、プロジェクト内のどのコンポーネントからでも呼び出せるため、開発効率が大幅にアップします。
さらなるステップアップ:Apollo Clientの活用
本記事では標準のfetch関数を用いたシンプルな実装を紹介しましたが、より大規模なアプリケーションを開発する場合には、Apollo ClientやRelayといった強力なライブラリの導入も検討してみてください。これらのライブラリを使用すると、取得したデータのキャッシュ管理や、リアルタイムなデータ更新(Subscription)、より高度なエラーハンドリングが簡単に行えるようになります。
例えば、TypeScriptを導入しているプロジェクトであれば、GraphQLのスキーマから型定義を自動生成するツール(GraphQL Code Generatorなど)を併用することで、型安全な開発環境を構築することも可能です。これにより、実行時のエラーを未然に防ぎ、チーム開発におけるコミュニケーションコストを下げることにも繋がります。
実践的なサンプルコード:検索機能の実装
ここで、もう少し実践的な例を見てみましょう。ユーザーが入力したIDに基づいて、動的にデータを取得するサーチコンポーネントの例です。
import React, { useState } from "react";
import useGraphQL from "./useGraphQL";
function UserSearch() {
const [userId, setUserId] = useState("1");
// IDに基づいて動的にクエリを生成
const query = `
{
user(id: "${userId}") {
id
name
status
}
}
`;
const { data, loading, error } = useGraphQL(query);
return (
<div className="container mt-4">
<h3 className="mb-3">ユーザー検索</h3>
<div className="input-group mb-3">
<input
type="text"
className="form-control"
value={userId}
onChange={(e) => setUserId(e.target.value)}
placeholder="ユーザーIDを入力"
/>
</div>
{loading && <div className="spinner-border text-primary" role="status"><span>読み込み中...</span></div>}
{error && <div className="alert alert-danger">データの取得に失敗しました。IDを確認してください。</div>}
{data && data.user && (
<div className="card shadow-sm">
<div className="card-body">
<h5 className="card-title">{data.user.name}</h5>
<p className="card-text">ステータス: {data.user.status}</p>
</div>
</div>
)}
</div>
);
}
export default UserSearch;
このように、Reactのステート(useState)とカスタムフックを連動させることで、ユーザーの操作に反応する動的なアプリケーションを驚くほどシンプルに記述できます。GraphQLのクエリはただの文字列ですので、JavaScriptのテンプレートリテラルを使えば変数の埋め込みも自由自在です。
モダンなウェブ開発において、フロントエンドとバックエンドの橋渡し役となるAPI通信の設計は非常に重要です。今回学んだ「GraphQL × カスタムフック」の組み合わせは、その設計を美しく、そして効率的に保つための強力な武器になるはずです。ぜひ、ご自身のプロジェクトでも積極的に取り入れて、クリーンなコードでの開発を楽しんでください。
生徒
「先生、まとめまで読んでカスタムフックの凄さがよく分かりました!今まで各コンポーネントにuseEffectをバラバラに書いていたのが、すごくもったいなく感じます。」
先生
「その気づきは素晴らしいですね!ロジックを一箇所に集約することで、後から修正が必要になった時も、カスタムフックのファイル一つを直すだけで済むようになります。これがメンテナンス性の向上ですね。」
生徒
「GraphQLについても、REST APIの時みたいに『このAPI、余計なデータが多いな……』って悩まなくていいのが最高です。クエリを書くのが少し独特ですけど、慣れたらこっちの方が直感的かもしれません。」
先生
「そうですね。特にモバイルアプリとの連携など、通信量を節約したい場面ではGraphQLの『必要な分だけ取る』という特性が大きな威力を発揮します。今回のサンプルで、loadingやerrorの状態も一緒に返している理由も分かりますか?」
生徒
「はい!通信中なのか、それとも失敗したのかをコンポーネント側で簡単に判断できるからですよね。これのおかげで、ユーザーに優しいUIが作りやすくなるんだなって実感しました。」
先生
「完璧な理解です!最初は難しく感じるかもしれませんが、まずは小さなプロジェクトからこのカスタムフックの形を取り入れてみてください。どんどんコードを書くのが楽しくなりますよ。」
生徒
「ありがとうございます!次は教えてもらったApollo Clientについても調べて、もっと高度なキャッシュ管理に挑戦してみようと思います!」