カスタムフックとは、Reactで共通するロジックを再利用可能な関数として切り出せる仕組みです。コンポーネント内のロジックが増えてきたときに、処理を整理して見通しを良くしてくれます。
この記事で学べること:
- カスタムフックの基本的な仕組みとルール
- カスタムフックを使うメリットと注意点
- カスタムフックを使ったデータ取得機能の実装例
カスタムフックの考え方を身につけると、「同じ処理を何度も書いている」という場面を減らし、コンポーネントをすっきり保てるようになります。ロジックの整理ができるようになることで、チーム開発でも読みやすいコードを書く力につながります。
Reactの開発環境の構築方法や、基本を復習したい方は以下の記事も参考にしてください。
Reactカスタムフックとは
カスタムフックとは、Reactの組み込みHook(useState、useEffectなど)を組み合わせて、独自の処理を持つ関数を作成できる仕組みです。共通する機能を1つのカスタムフックにまとめることで、複数のコンポーネントから同じロジックを呼び出せるようになります。
カスタムフックを使用するメリット
カスタムフックを使用する主なメリットは以下の2つです。
-
同じ処理を1つに集約
複数のコンポーネントで使う共通のロジックをカスタムフックにまとめることで、同じコードを何度も書く必要がなくなります。修正が必要になった場合もカスタムフックだけを直せば済むため、メンテナンスも楽になります。
-
コンポーネントのViewとロジックを分離
コンポーネント内にロジックが増えると、コードの見通しが悪くなりがちです。カスタムフックにロジックを切り出すことで、コンポーネントはUI(表示)に集中でき、役割が明確になります。

図:カスタムフックを使用するメリット
複数のコンポーネントで使う共通のロジックを見つける

図:カスタムフックを使用するメリットと効果
共通のロジックをカスタムフックにまとめ、コードのメンテナンス性が向上する
カスタムフックのルール
カスタムフックの作成には、以下の2つのルールがあります。
-
Reactの組み込みフックを含む関数
カスタムフックは、内部で
useStateやuseEffectなどの組み込みフックを呼び出す関数です。フックを含まない関数は、通常の関数として扱います。 -
「use」で始まる関数名
カスタムフックの名前は必ず
useで始めます。これにより、Reactがその関数をフックとして認識し、使い方に誤りがある場合に警告を出してくれます。
Reactには「フックは関数のトップレベルでのみ呼び出す」というルールがあります。条件分岐の中でフックを呼び出すと、レンダリングごとに呼び出し順序が変わり、状態管理の一貫性が失われる可能性があるためです。useの命名規則に従うことで、この制約がコード上で明確になり、予期しない不具合の防止に役立ちます。
Reactカスタムフックの使い方
useStateを使ったカウントアップ機能をカスタムフックに切り出す流れをコード例で確認します。まず、組み込みフックだけで実装したカウントアップアプリのコードです。
App.jsx
// App.jsx 組み込みフックを使用した記述
import { useState } from 'react';
import Button from './components/Button';
export default function App() {
const [count, setCount] = useState(0);
const increment = () => {
setCount((count) => count + 1);
};
const doubleIncrement = () => {
setCount((count) => count + 2);
};
return (
<>
<Button onClick={increment} text={'+1'} />
<Button onClick={doubleIncrement} text={'+2'} />
<p>Count : {count}</p>
</>
);
}
Button.jsx
// Button.jsx
export default function Button({ onClick, text }) {
return <button onClick={onClick}>{text}</button>;
}
+1ボタンと+2ボタンをクリックすると、指定の数だけカウントが増えるシンプルなアプリです。

次に、useStateでのカウントアップ機能をカスタムフックとして切り出します。新しくuseCountUp.jsxファイルを作成し、各ファイルを以下のように編集します。
useCountUp.jsx
// useCountUp.jsx カスタムフックを使用した記述
import { useState } from 'react';
export default function useCountUp() {
const [count, setCount] = useState(0);
const increment = () => {
setCount((count) => count + 1);
};
const doubleIncrement = () => {
setCount((count) => count + 2);
};
// カスタムフックの戻り値をオブジェクトで指定
return { count, increment, doubleIncrement };
}
App.jsx
// App.jsx カスタムフックを使用した記述
import useCountUp from './hooks/useCountUp';
import Button from './components/Button';
export default function App() {
const { count, increment, doubleIncrement } = useCountUp();
return (
<>
<Button onClick={increment} text={'+1'} />
<Button onClick={doubleIncrement} text={'+2'} />
<p>Count : {count}</p>
</>
);
}
Button.jsx
// Button.jsx
// このファイルはカスタムフック作成前と変更はありません
export default function Button({ onClick, text }) {
return <button onClick={onClick}>{text}</button>;
}
カスタムフックとしてuseCountUpを作成し、App.jsxからカウントアップ機能を切り離しました。機能が独立したモジュールにまとまり、複数のコンポーネントで再利用しやすくなっています。

戻り値はcount、increment、doubleIncrementの3つをオブジェクトにまとめています。オブジェクトで返すことで、呼び出し側は必要な値だけを柔軟に取り出せます。
カスタムフックの役割とstateについて
カスタムフックを使うと、同じロジックを複数のコンポーネントで再利用できます。ただし、同じカスタムフックを呼び出しても、各コンポーネントのstateはそれぞれ独立して保持されます。
複数のコンポーネントでstateを共有したい場合は、親コンポーネントからpropsで渡すか、useContextなどでグローバルに管理する方法があります。
カスタムフックの戻り値
カスタムフックの戻り値に決まったルールはありません。ただし、useStateと同じように「state → 操作する関数」の順序で返すと、直感的で使いやすくなります。
オブジェクトで返す設計にしておくと、後から機能やデータを追加しやすく、長期的な拡張にも対応できます。
カスタムフックの注意点
すべての重複コードをカスタムフックにする必要はありません。今回のようなシンプルな機能では、カスタムフックにするメリットが小さい場合もあります。
カスタムフックが特に有効なのは、useEffectを使ったAPI連携など、コードが複雑化しやすい処理や、多くのコンポーネントで共通するロジックをまとめたい場合です。
カスタムフックを作ってみよう
ここまでカスタムフックの基本とその使用方法を学んできました。このセクションでは実際にハンズオン形式でコードを記述し、さらに理解を深めていきましょう。
このハンズオンではJSONPlaceholderからデータを取得するカスタムフックを作成します。JSONPlaceholderは、開発者がAPIを使ってデータ取得や表示の練習ができる無料のサービスです。
また、ブラウザ上で直接コードを試してみたい場合は、以下のサイトがおすすめです。フロントエンドの環境構築が不要で、すぐにコードを記述し実行できます。
カスタムフックを利用したデータ取得機能の作成
このハンズオンでは、以下のファイルを作成します。
- App.jsx
- useFetchData.jsx
- UserList.jsx
- UserPosts.jsx
ファイルディレクトリは以下の階層としています。
src
├── App.jsx
├── hooks
│ └── useFetchData.jsx
└── components
├── UserList.jsx
└── UserPosts.jsx
各ファイルを編集します。
App.jsx
// App.jsx
import React from 'react';
import './App.css';
import UserList from './components/UserList';
import UserPosts from './components/UserPosts';
export default function App() {
return (
<>
<UserList />
<UserPosts />
</>
);
}
useFetchData.jsx
// useFetchData.jsx
import { useState, useEffect } from 'react';
function useFetchData(url) {
const [data, setData] = useState(null); // 取得したデータを保存するstate
const [loading, setLoading] = useState(true); // データ取得中かどうかを示すstate
const [error, setError] = useState(null); // エラーがあればエラーメッセージを保存するstate
useEffect(() => {
const fetchData = async () => {
setLoading(true); // データ取得開始時にロード中の表示をオン
try {
const response = await fetch(url); // 非同期でデータを取得
if (!response.ok) {
throw new Error('データの取得に失敗しました'); // データ取得に失敗した場合のエラーハンドリング
}
const result = await response.json(); // レスポンスをJSON形式に変換
setData(result); // 取得したデータをstateに保存
} catch (error) {
setError(error.message); // エラーメッセージをstateに保存
} finally {
setLoading(false); // データ取得完了後にロード中の表示をオフ
}
};
fetchData();
}, [url]);
return { data, loading, error }; // コンポーネントで使えるように状態を返す
}
export default useFetchData;
UserList.jsx
// UserList.jsx
import React from 'react';
import useFetchData from '../hooks/useFetchData';
export default function UserList() {
const { data, loading, error } = useFetchData('<https://jsonplaceholder.typicode.com/users>');
if (loading) return <p>Loading...</p>;
if (error) return <p>{error}</p>;
return (
<div>
<h2>User List</h2>
<ul>
{data.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
}
UserPosts.jsx
// UserPosts.jsx
import React from 'react';
import useFetchData from '../hooks/useFetchData';
export default function UserPosts() {
const { data, loading, error } = useFetchData(
'<https://jsonplaceholder.typicode.com/posts>'
);
if (loading) return <p>Loading...</p>;
if (error) return <p>{error}</p>;
return (
<div>
<h2>Posts List</h2>
<ul>
{data.map((post) => (
<li key={post.id}>
<h3>{post.title}</h3>
<p>{post.body}</p>
</li>
))}
</ul>
</div>
);
}
コード編集後、以下のようなUIが作成できるかと思います。UserとPostsデータを取得し、画面に表示されています。

今回のハンズオンではカスタムフックを作成して、データを取得するフックを作成しました。
カスタムフックの効果
カスタムフックを使うことで、データ取得のロジックがシンプルになり、どちらのコンポーネントでも同じようにデータ取得が可能です。UserListとUserPostsでは、URLを変更するだけで異なるAPIデータを取得でき、データ取得後の処理もシンプルに書けるようになっています。
UserList.jsx
// UserList.jsx
export default function UserList() {
const { data, loading, error } = useFetchData(
'<https://jsonplaceholder.typicode.com/users>' // URLが異なる
);
if (loading) return <p>Loading...</p>;
if (error) return <p>{error}</p>;
UserPosts.jsx
// UserPosts.jsx
export default function UserPosts() {
const { data, loading, error } = useFetchData(
'<https://jsonplaceholder.typicode.com/posts>' // URLが異なる
);
if (loading) return <p>Loading...</p>;
if (error) return <p>{error}</p>;
このように、useFetchDataというカスタムフックを使うことで、複数のコンポーネントでデータ取得の処理をシンプルに再利用できるのがポイントです。
Reactカスタムフックに関するよくある質問
Reactカスタムフックに関するよくある質問を、以下の通りにまとめました。
Q. カスタムフックと通常の関数は何が違う?
カスタムフックは内部でuseStateやuseEffectなどの組み込みHookを呼び出す関数です。組み込みHookを含まない関数は通常の関数として扱い、関数名に「use」をつける必要はありません。
Q. カスタムフックはどのタイミングで作るべき?
同じロジックを複数のコンポーネントで使い回す場面や、コンポーネント内のロジックが増えて見通しが悪くなったときが目安です。最初からカスタムフックにする必要はなく、必要性を感じたタイミングで切り出すのが自然な進め方です。
Q. カスタムフックの中でuseEffectは使える?
使えます。API連携やイベントリスナーの登録など、useEffectを含むロジックをカスタムフックにまとめるのはよくあるパターンです。
Q. 1つのカスタムフックに複数のHookを入れてもいい?
問題ありません。useState、useEffect、useRefなど、必要に応じて複数の組み込みHookを1つのカスタムフックにまとめられます。関連するロジックを1つにまとめることで、コンポーネント側のコードがすっきりします。
まとめ
この記事では、Reactカスタムフックの仕組みと使い方について解説しました。
学んだ内容:
この記事の要点は以下の通りです。
- カスタムフックは組み込みHookを組み合わせて独自のロジックを切り出せる仕組み
- 共通ロジックの再利用とUIからのロジック分離が主なメリット
- 関数名を「use」で始め、組み込みフックを含むことが作成ルール
- 各コンポーネントのstateは同じカスタムフックを使っても独立
- シンプルすぎる処理には不要、複雑なロジックや共通処理に有効
カスタムフックが作れるようになると、コンポーネントの役割を整理しながら開発を進められるようになります。まずは今回のカウントアップのような小さな処理から試し、慣れてきたらAPI連携やフォーム管理など、実務で使える場面に応用してみてください。
参考資料
以下のリンクは、この記事で説明した手順や概念に関連する参考資料です。より詳しく学びたい方は、ぜひご覧ください。
【番外編】USBも知らなかった私が独学でプログラミングを勉強してGAFAに入社するまでの話

プログラミング塾に半年通えば、一人前になれると思っているあなた。それ、勘違いですよ。「なぜ間違いなの?」「正しい勉強法とは何なの?」ITを学び始める全ての人に知って欲しい。そう思って書きました。是非読んでみてください。
「フリーランスエンジニア」
近年やっと世間に浸透した言葉だ。ひと昔まえ、終身雇用は当たり前で、大企業に就職することは一種のステータスだった。しかし、そんな時代も終わり「優秀な人材は転職する」ことが当たり前の時代となる。フリーランスエンジニアに高価値が付く現在、ネットを見ると「未経験でも年収400万以上」などと書いてある。これに釣られて、多くの人がフリーランスになろうとITの世界に入ってきている。私もその中の1人だ。数年前、USBも知らない状態からITの世界に没入し、そこから約2年間、毎日勉学を行なった。他人の何十倍も努力した。そして、企業研修やIT塾で数多くの受講生の指導経験も得た。そこで私は、伸びるエンジニアとそうでないエンジニアをたくさん見てきた。そして、稼げるエンジニア、稼げないエンジニアを見てきた。
「成功する人とそうでない人の違いは何か?」
私が出した答えは、「量産型エンジニアか否か」である。今のエンジニア市場には、量産型エンジニアが溢れている!!ここでの量産型エンジニアの定義は以下の通りである。
比較的簡単に学習可能なWebフレームワーク(WordPress, Rails)やPython等の知識はあるが、ITの基本概念を理解していないため、単調な作業しかこなすことができないエンジニアのこと。
多くの人がフリーランスエンジニアを目指す時代に中途半端な知識や技術力でこの世界に飛び込むと返って過酷な労働条件で働くことになる。そこで、エンジニアを目指すあなたがどう学習していくべきかを私の経験を交えて書こうと思った。続きはこちらから、、、、
エンベーダー編集部
エンベーダーは、ITスクールRareTECHのインフラ学習教材として誕生しました。 「遊びながらインフラエンジニアへ」をコンセプトに、インフラへの学習ハードルを下げるツールとして運営されています。

関連記事

2025.06.26
【React入門】useStateの使い方|動的なコンポーネント作成の第一歩
ReactのuseStateフックを使い、動的なUIを作る方法を解説。stateの宣言から更新まで、カウンターアプリの作成を通して基本を学びます。
- React
- フロントエンド

2026.03.14
React useRefとは?使い方とrefとstateの違いを初心者向けに解説
React useRefとは、再レンダリングなしで値を保持したりDOM要素に直接アクセスできるHookです。stateとの違いや基本の使い方を、自動スクロール機能の実装例を交えて解説します。
- React
- フロントエンド

2026.03.07
初心者にもわかるReactのインストールと基礎知識を解説
Reactの開発環境の構築方法を初心者向けに解説。Node.jsの導入からViteを使ったプロジェクト作成、起動確認、基本概念まで手順に沿って学べます。
- フロントエンド
- ハンズオン
- React
- JavaScript

2024.03.24
JavaScriptって何?レベルの初心者がとりあえず触ってみるハンズオン
このハンズオンを通じて、プログラミング初心者やJavaScriptに苦手意識を持つ方でも、JavaScriptの使い方を基礎から簡単に学べます。特別な経験や知識は一切必要ありません。パソコンとインターネットの基本操作ができれば、準備は完了です。わからないことがあっても大丈夫。一旦はこういうものだと思って進めてみてください。
- ハンズオン
- JavaScript
- フロントエンド



