ReactのuseFetchカスタムフックを作成する基本!初心者でもわかるAPIデータ取得
生徒
「ReactでAPIからデータを取ってくるときに、毎回同じようなコードを書いていて大変なんです…もっと楽にできませんか?」
先生
「そんなときに便利なのがカスタムフックです。特にAPI管理にはuseFetchというカスタムフックを作るのが基本的な方法なんですよ。」
生徒
「useFetchって名前はよく見ますけど、どんな役割を持っているんですか?」
先生
「APIからデータを取る処理をひとまとめにした便利な道具のようなものです。では、作り方を一緒に学んでいきましょう!」
1. useFetchカスタムフックとは?
useFetchは、APIからデータを取得する処理をひとつにまとめたカスタムフックです。毎回コンポーネントの中にfetch関数やuseEffectを書かなくても、このフックを呼び出すだけで同じ処理を再利用できます。
例えば、料理をするときに毎回スパイスを調合するのは面倒ですが、「カレー粉」があれば一瞬で味が決まりますよね。useFetchも同じで、APIの処理をひとまとめにすることで、どのコンポーネントでも簡単に使えるようになります。
さらに、初心者がつまずきやすい「状態管理」や「非同期処理」も内部でまとめて処理できるので、コードがスッキリして理解しやすくなるというメリットがあります。
2. useFetchカスタムフックを作る基本コード
ここではシンプルなuseFetchを作ってみましょう。外部からURLを渡して、そのデータを取得する仕組みです。
import { useState, useEffect } from "react";
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
setLoading(true);
fetch(url)
.then((res) => {
if (!res.ok) {
throw new Error("エラーが発生しました");
}
return res.json();
})
.then((json) => {
setData(json);
setLoading(false);
})
.catch((err) => {
setError(err.message);
setLoading(false);
});
}, [url]);
return { data, loading, error };
}
export default useFetch;
このuseFetchフックを作っておくことで、どのコンポーネントでも使えるようになります。
3. useFetchを使った具体的な利用例
実際にuseFetchを呼び出してみましょう。以下はデータを一覧表示するコンポーネントです。
import React from "react";
import useFetch from "./useFetch";
function App() {
const { data, loading, error } = useFetch("https://api.example.com/items");
if (loading) return <p>読み込み中...</p>;
if (error) return <p>エラー: {error}</p>;
return (
<div>
<h1>商品一覧</h1>
<ul>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
);
}
export default App;
4. useFetchを使うメリット
実際にカスタムフックを使うと、次のようなメリットがあります。
- コードの再利用性が高い:何度も同じ処理を書かなくてよい
- コンポーネントが読みやすい:UIの見た目とデータ処理を分けられる
- エラー処理も一元化:API失敗時の対応をひとつの場所で管理できる
- 保守が簡単:仕様変更があっても修正箇所が少なく済む
初心者にとって特に大切なのは「コードがシンプルに見える」点です。余計なコードが減ることで、どこで何をしているのかが理解しやすくなります。
5. 初心者が気をつけるべきポイント
useFetchを使うときにはいくつか注意点があります。
- カスタムフックの名前は必ず
useから始めること - フックは条件分岐やループの中で呼び出してはいけないこと
- 非同期処理のため、必ず「読み込み中」の状態を用意すること
これらはReactのルールに沿って正しく動かすための基本です。最初は難しく感じるかもしれませんが、決まり事として覚えてしまえば自然に使えるようになります。
6. 実際のアプリ開発での活用イメージ
例えば、ブログアプリで記事の一覧を表示したり、天気アプリで現在の天気を取得したりするときに、このuseFetchを使えば簡単にAPIと連携できます。
また、複数のAPIを扱うときも、使い方は同じなので学習コストが下がります。チーム開発でも共通のuseFetchを用意すれば、みんなが統一された方法でデータを扱えるようになります。
まとめ
ここまでReactにおけるAPIデータ取得の効率化、特にuseFetchカスタムフックの自作方法とその活用シーンについて詳しく解説してきました。React開発において、コンポーネント内に直接データ取得ロジックを記述する方法は、小規模なプロジェクトであれば問題ありませんが、アプリの規模が大きくなるにつれてコードの重複や管理の複雑さを招く原因となります。
今回学んだ「カスタムフック」という仕組みは、Reactの関数コンポーネントのロジックを抽出し、再利用可能にするための強力な武器です。特にAPI通信のような「リクエストの開始」「データの格納」「読み込み中状態の管理」「エラーハンドリング」という一連の流れは、ほとんどの画面で共通して発生するものです。これらをuseFetchとして一つの関数にまとめることで、プロジェクト全体のコード品質を劇的に向上させることができます。
API通信をさらに柔軟にする応用的な拡張
基本のuseFetchをマスターしたら、次はさらに実用的な機能を加えてみましょう。例えば、APIのURLだけでなく、リクエストのオプション(GETやPOSTなどのメソッド指定)を渡せるようにしたり、依存配列を調整して「特定のボタンを押したときだけ再取得する(refetch機能)」を追加したりすることが一般的です。
また、最新のReact開発では「React Query (TanStack Query)」や「SWR」といった、カスタムフックによるデータ取得をより高度に自動化したライブラリも広く使われています。これらも内部的には今回学習したようなカスタムフックの考え方がベースになっています。まずは自作のuseFetchで「状態の変化がどのようにUIに反映されるか」という基本原理をしっかり理解することが、プロフェッショナルなエンジニアへの近道です。
型安全な開発を目指すためのTypeScript対応(TSX例)
最近の開発現場では、JavaScriptに型定義を追加したTypeScript(TSX)が主流です。型を指定することで、APIからどんなデータが返ってくるのかをエディタが把握し、ケアレスミスを未然に防いでくれます。参考までに、useFetchをTypeScriptで記述した場合のコードも確認しておきましょう。
import { useState, useEffect } from "react";
/**
* 型安全なAPIデータ取得用カスタムフック
* Tには期待するレスポンスの型を渡します
*/
function useFetch<T>(url: string) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error("データの取得に失敗しました");
}
const result = await response.json();
setData(result);
} catch (err: any) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
export default useFetch;
このように、Generics(<T>)を使うことで、どんなデータ形式にも対応できる汎用的なフックが作成できます。これにより、コンポーネント側でdataを扱う際、プロパティ名の入力補完が効くようになり、開発効率がさらに向上します。
実務で差がつく!パフォーマンスとクリーンアップ
さらに一歩進んだテクニックとして、コンポーネントがアンマウント(画面から消える)された際の処理も重要です。例えば、データの読み込みが終わる前にユーザーが別のページに移動した場合、バックグラウンドで動き続けている通信をキャンセル(AbortControllerを使用)する処理を追加すると、メモリリークを防ぎ、より堅牢なアプリケーションになります。
初心者のうちは、まずは「動くものを作る」ことが大切ですが、慣れてきたら「どうすればもっと効率よく、安全に動くか」を意識してみてください。今回学んだuseFetchの構築プロセスは、他のあらゆるカスタムフック作成(フォーム入力管理やスクロール検知など)にも応用できる、フロントエンドエンジニアにとっての必須スキルです。
生徒
「先生、ありがとうございました!useFetchを作ることで、App.jsがすごく短くなって驚きました。今まではAPIを叩くたびにuseStateを3つも4つも書いていたので、あれが全部消えるのは快感ですね。」
先生
「その感覚はとても大切ですよ。コードが整理されると、本来注力すべき『ユーザーに見せる画面(UI)』の作成に集中できますからね。カスタムフックの真価は、一度作れば他のプロジェクトでもコピペして使える『資産』になるところにあります。」
生徒
「資産、いい響きですね。さっそく自分が作っているポートフォリオにも導入してみます。ちなみに、複数のURLから同時にデータを取得したい場合も、このuseFetchを複数回呼び出すだけでいいんですか?」
先生
「その通りです。const { data: userData } = useFetch('/api/user')のように、分割代入で名前を変えて呼び出せば、一つのコンポーネントで複数のAPIをスマートに扱えます。ただし、呼び出しすぎると画面がバラバラに表示されてしまうので、ローディングの出し方を工夫するなど、UX(ユーザー体験)の設計も考えてみると面白いですよ。」
生徒
「なるほど。ただデータを取ってくるだけでなく、どう見せるかもセットで考える必要があるんですね。TypeScript版の書き方も教えてもらったので、型定義にも挑戦して、より『壊れにくいコード』を目指してみます!」
先生
「素晴らしい意気込みですね。Reactの世界は、基本を組み合わせることで無限に可能性が広がります。ぜひ、自分なりに使いやすい最強のuseFetchに育て上げてみてください。応援していますよ!」