カスタムフックでAPI通信を共通化する方法をやさしく解説!React初心者でもわかるフックの使い方
生徒
「ReactでAPI通信を毎回同じように書くのが面倒なんですけど、もっと簡単にできませんか?」
先生
「それなら、カスタムフックを使う方法があります。API通信の処理をまとめて使い回せるんです。」
生徒
「カスタムフックって自分で作れるんですか?」
先生
「もちろんです!一度作っておけば、どのコンポーネントからでも簡単に使えます。実際の作り方を見てみましょう。」
1. カスタムフックとは?
まず「カスタムフック」とは、Reactで自分で作るフック(useStateやuseEffectのような関数)です。フックとは、Reactの機能を関数の中で使うための仕組みのことを指します。
Reactにはあらかじめ用意されている「組み込みフック」がありますが、カスタムフックを使うと、複数のコンポーネントで共通する処理をまとめて再利用できるようになります。
たとえば、「APIからデータを取得する処理」を毎回コンポーネントに書くと、コードが重複してしまいます。そんなときに、カスタムフックを使えば次のようにスッキリ書けます。
2. API通信をコンポーネントに直接書くとどうなる?
まず、API通信をコンポーネントに直接書いた例を見てみましょう。
import React, { useState, useEffect } from "react";
function UserList() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => response.json())
.then((data) => setUsers(data));
}, []);
return (
<div>
<h2>ユーザー一覧</h2>
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
}
export default UserList;
このように書くと動作はしますが、他の画面でもAPIを使いたい場合に同じ処理をもう一度書かなければなりません。これではコードの重複が増えてしまいます。
3. カスタムフックでAPI通信を共通化しよう
ここで登場するのがカスタムフックです。API通信の処理を共通化しておけば、他のコンポーネントからも簡単に呼び出せます。
カスタムフックは「use」から始まる関数名で作るのがルールです。たとえば「APIを取得するフック」を作る場合は、useFetchのように名付けます。
import { useState, useEffect } from "react";
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
if (!response.ok) throw new Error("通信エラーが発生しました");
const result = await response.json();
setData(result);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
export default useFetch;
このuseFetchフックを使えば、どんなAPI通信も簡単に再利用できます。
4. カスタムフックを使ってAPI通信を呼び出す
先ほどのuseFetchを使って、ユーザー一覧を取得するコンポーネントを作ってみましょう。
import React from "react";
import useFetch from "./useFetch";
function UserList() {
const { data: users, loading, error } = useFetch(
"https://jsonplaceholder.typicode.com/users"
);
if (loading) return <p>読み込み中です...</p>;
if (error) return <p>エラー: {error}</p>;
return (
<div>
<h2>ユーザー一覧</h2>
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
}
export default UserList;
このようにカスタムフックを使えば、データの取得・エラー処理・ローディング表示を簡単に共通化できます。
5. カスタムフックを使うメリット
- コードの再利用性が高い:同じAPI通信処理を何度も書く必要がなくなります。
- コードが読みやすくなる:コンポーネントにはUIの部分だけを残せます。
- 保守性が上がる:API処理を変更したいときは、カスタムフックだけ修正すれば全体に反映されます。
React開発では、カスタムフックを使って「ロジック(処理)」と「UI(見た目)」を分離することがとても重要です。これにより、チーム開発でもコードが整理され、後から機能を追加するのも簡単になります。
6. さらに発展:複数のAPIを扱う場合
もし複数のAPIを同時に扱いたい場合でも、カスタムフックを少し工夫すれば対応できます。たとえば、POST通信を追加したり、リトライ機能を付けたりすることも可能です。
まずは基本形のuseFetchをしっかり理解して、次にusePostなどの別フックを作ると、より柔軟なAPI管理ができるようになります。
まとめ
ReactでAPI通信を共通化するためのカスタムフックについて振り返ると、まずカスタムフックそのものが「複数のコンポーネントで繰り返し使う処理をまとめて再利用できる仕組み」であることを深く理解できました。特にAPI通信のように、どの画面でも似たような動作を必要とする機能はカスタムフックとの相性が良く、React開発の中でも頻繁に利用される実践的なパターンとなります。通信処理をコンポーネントに毎回書いてしまうと、コードが長くなり、同じような処理がアプリ全体で点在してしまいますが、カスタムフックを作ることで、ロジックをきれいにまとめられ、見通しの良い構造に整理できます。 また、API通信を扱う際には「読み込み中」「成功時」「エラー時」という三つの状態を明確に管理することが重要であり、その点もカスタムフックが大きく役立ちます。useStateで状態を持ち、useEffectでAPIを呼び出すという流れをひとつの関数にまとめることで、UI側ではデータの表示だけに集中できるようになり、コンポーネントがより直感的で理解しやすくなります。さらに、通信中のユーザービリティ向上のためのローディング表示、エラー発生時のメッセージ表示なども、カスタムフック内にまとめることで統一した動作が実現できるため、開発効率も品質も高める結果になります。 API通信では、ネットワークエラー、ステータスコードの異常、データ形式の不一致など、実際の運用に近づくほど多くの問題が発生しがちですが、これらを包括的に管理する仕組みとしてカスタムフックは大変便利です。初心者の段階でこの構造を理解しておくことで、後に規模が大きくなっても無理なく対応できる開発力が身につきます。また、複数のAPIエンドポイントを扱うようになった場合も、同じフックを呼ぶだけで統一された挙動を得られるため、保守性や拡張性の面でも優れています。 今回の学習を通して、ReactでのロジックとUIの分離、再利用可能なコードの書き方、安定したAPI通信の扱い方など、フロントエンド開発で必要な基礎がしっかりと理解できたはずです。こうした考え方はReactに限らず、他のモダンフレームワークにも通じる重要な設計思想であり、今後の学習にも大いに役立つでしょう。
API通信を共通化するカスタムフックの再掲
学習の振り返りとして、API通信を共通化するカスタムフックuseFetchのコードを再掲します。
import { useState, useEffect } from "react";
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
if (!response.ok) throw new Error("通信エラーが発生しました");
const result = await response.json();
setData(result);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
export default useFetch;
このフックは、指定したURLをもとにAPI通信を行い、データ・エラー・ローディング状態を返す仕組みです。どのコンポーネントからでも呼び出すだけで利用できることから、React開発の効率を大きく向上させます。さらにエラーハンドリングや読み込み状態もこのひとつのフックで一元管理できるため、UI側のコードは必要最小限となり、可読性が高く直感的に理解できる構造になります。API通信を扱う場面が増えるほど、このようなフックを用意することの価値を実感できるでしょう。
生徒
「API通信を毎回コンポーネントに書いていたんですが、カスタムフックにまとめればすごくスッキリするんですね!」
先生
「その通りです。ロジックを共通化することで、コードの重複が減り、開発がかなり楽になりますよ。」
生徒
「useFetchを使えば、読み込み中やエラー処理も全部まとめて扱えるので便利だと感じました。」
先生
「用途に合わせてPOST用のフックを作ったり、リトライ機能を追加したりと応用もたくさんできます。基礎を理解したので、これからさらに広げていけますね。」
生徒
「はい!次はもっと複雑なAPIも扱ってみたいです!」