カテゴリ: React 更新日: 2026/01/08

Reactのカスタムフックでイベントリスナーを共通化する方法!初心者でも理解できるReact Hooks入門

カスタムフックでイベントリスナーを共通化する方法
カスタムフックでイベントリスナーを共通化する方法

先生と生徒の会話形式で理解しよう

生徒

「Reactでスクロールやクリックなどのイベントを複数のコンポーネントで使いたいとき、毎回書くのが面倒なんですが…」

先生

「それは良いところに気づきました。そんなときに使えるのが『カスタムフック』です。」

生徒

「カスタムフックって、自分で作るReactのフックのことですか?」

先生

「その通りです。今回は、イベントリスナー(イベントを検知して動作する仕組み)をカスタムフックで共通化する方法を学びましょう。」

1. カスタムフックとは?

1. カスタムフックとは?
1. カスタムフックとは?

まず「カスタムフック(Custom Hook)」とは、Reactで用意されているuseStateuseEffectなどのフックを組み合わせて、 自分専用の「use〇〇」という関数を作る仕組みのことです。Reactでは、同じ処理を何度も書くよりも、共通化して再利用する考え方がとても重要になります。

たとえば「画面の操作を監視する」「状態を管理する」といった処理を、コンポーネントごとに書いていると、コードが長くなり理解しづらくなります。 カスタムフックを使えば、そのような処理をひとまとめにでき、初心者でも読みやすく整理されたReactコードを書くことができます。

イベントリスナーのように「何かの動きを検知して処理を行う」仕組みは、カスタムフックと非常に相性が良く、 一度作っておけば複数のコンポーネントで安全に使い回せるようになります。


import { useState } from "react";

function useMessage() {
  const [message, setMessage] = useState("こんにちは!");
  return { message, setMessage };
}

export default useMessage;
(画面に「こんにちは!」と表示され、ボタンを押すと別のメッセージに切り替わります)

このように、カスタムフックは「処理のまとまり」を作るための仕組みです。 React初心者の方は、まずは「同じ処理を何度も書いていないか」を意識しながら、 少しずつカスタムフックに分ける練習をすると理解が深まります。

2. イベントリスナーとは?

2. イベントリスナーとは?
2. イベントリスナーとは?

「イベントリスナー」とは、ユーザーが画面上で行った操作をきっかけに、あらかじめ決めておいた処理を実行する仕組みのことです。 たとえば、ボタンをクリックしたとき、画面をスクロールしたとき、キーボードを押したときなど、 Webページ上で起こるさまざまな動きを検知して反応する役割を持っています。

プログラミング未経験の方でも、「ボタンを押したら文字が変わる」「マウスを動かしたら表示が変わる」といった動きは、 日常的にWebサイトで見かけているはずです。これらの裏側では、イベントリスナーがユーザーの操作を常に監視し、 決められたタイミングで処理を呼び出しています。


import React, { useState } from "react";

function ClickMessage() {
  const [text, setText] = useState("こんにちは!");

  function handleClick() {
    setText("ボタンがクリックされました!");
  }

  return (
    <div style={{ textAlign: "center" }}>
      <p>{text}</p>
      <button onClick={handleClick}>クリック</button>
    </div>
  );
}

export default ClickMessage;
(画面に「こんにちは!」と表示され、ボタンを押すと「ボタンがクリックされました!」に変わります)

この例では、「クリックする」というイベントに反応して文字を変更しています。 Reactでは、このようなイベント処理をコンポーネントの中に書くことができますが、 同じようなイベントリスナーを複数のコンポーネントで使い始めると、コードが増えて管理が難しくなります。

そのため、イベントリスナーをまとめて扱える仕組みが重要になります。 後ほど紹介するカスタムフックを使えば、イベント処理を共通化し、 Reactアプリ全体をシンプルで分かりやすい構造に整理できるようになります。

3. useEventListenerフックを作ってみよう

3. useEventListenerフックを作ってみよう
3. useEventListenerフックを作ってみよう

まずは、どんなイベントでも簡単に登録できるような汎用的なカスタムフックを作ります。


import { useEffect } from "react";

function useEventListener(eventType, handler, element = window) {
  useEffect(() => {
    if (!element) return;

    // イベントを登録
    element.addEventListener(eventType, handler);

    // クリーンアップ(コンポーネントが消えるときに解除)
    return () => {
      element.removeEventListener(eventType, handler);
    };
  }, [eventType, handler, element]);
}

export default useEventListener;

このカスタムフックでは、useEffectを使って、イベントの登録と解除を自動で行っています。
つまり、このフックを使うだけで、コンポーネントごとに同じイベントリスナーを書く必要がなくなります。

4. カスタムフックを使ってスクロールイベントを共通化する

4. カスタムフックを使ってスクロールイベントを共通化する
4. カスタムフックを使ってスクロールイベントを共通化する

次に、このuseEventListenerを使って、スクロール量を監視する例を見てみましょう。


import React, { useState } from "react";
import useEventListener from "./useEventListener";

function ScrollTracker() {
  const [scrollY, setScrollY] = useState(0);

  // スクロールイベントを監視して状態を更新
  useEventListener("scroll", () => {
    setScrollY(window.scrollY);
  });

  return (
    <div style={{ height: "200vh", padding: "20px" }}>
      <h2>現在のスクロール位置: {scrollY}px</h2>
    </div>
  );
}

export default ScrollTracker;
(画面をスクロールすると、「現在のスクロール位置: ○○px」とリアルタイムで数値が変化します)

このように、useEventListenerを使えば、イベント処理をシンプルに書けるようになります。

5. 複数のイベントでも使える便利な共通化

5. 複数のイベントでも使える便利な共通化
5. 複数のイベントでも使える便利な共通化

このuseEventListenerフックは、クリックやキー入力などにも使えます。


import React, { useState } from "react";
import useEventListener from "./useEventListener";

function MouseTracker() {
  const [position, setPosition] = useState({ x: 0, y: 0 });

  // マウスの動きを監視
  useEventListener("mousemove", (e) => {
    setPosition({ x: e.clientX, y: e.clientY });
  });

  return (
    <div style={{ height: "100vh", textAlign: "center" }}>
      <h2>マウス位置: X={position.x}, Y={position.y}</h2>
    </div>
  );
}

export default MouseTracker;
(マウスを動かすと、X座標とY座標がリアルタイムで表示されます)

このように、同じuseEventListenerを使い回せるので、コードの重複が減り、保守性(あとで修正しやすくすること)も向上します。

6. カスタムフックでコードを整理するメリット

6. カスタムフックでコードを整理するメリット
6. カスタムフックでコードを整理するメリット

カスタムフックでイベントリスナーを共通化するメリットは次のとおりです。

  • ① コードの重複を減らせる
  • ② イベントの登録・解除を自動で行える
  • ③ コンポーネントのロジックをスッキリ整理できる

たとえば、通常ならuseEffectでイベントを登録し、クリーンアップするコードを毎回書く必要がありますが、useEventListenerなら1行で済みます。

プログラムの保守やバグ修正が簡単になるため、実際の現場でもよく使われる設計パターンです。

7. イベント対象を自由に変える応用例

7. イベント対象を自由に変える応用例
7. イベント対象を自由に変える応用例

さらに、第三引数に特定の要素(例えばdocumentや特定のDOM要素)を渡すことで、より柔軟な制御が可能になります。


import React, { useRef, useState } from "react";
import useEventListener from "./useEventListener";

function BoxClickTracker() {
  const boxRef = useRef(null);
  const [count, setCount] = useState(0);

  // 特定の要素(boxRef)にクリックイベントを追加
  useEventListener("click", () => setCount(count + 1), boxRef.current);

  return (
    <div>
      <div
        ref={boxRef}
        style={{
          width: "200px",
          height: "200px",
          backgroundColor: "lightblue",
          margin: "20px auto",
        }}
      ></div>
      <h2>クリック回数: {count}</h2>
    </div>
  );
}

export default BoxClickTracker;
(水色のボックスをクリックするたびに、クリック回数が1ずつ増えていきます)

このように、ウィンドウ全体だけでなく特定の要素にもイベントを付与できるのが大きな特徴です。

8. ポイント整理

8. ポイント整理
8. ポイント整理

ここまで見てきたように、イベントリスナーをカスタムフックとして共通化すると、Reactアプリ全体の構造がとても分かりやすくなります。 クリックやスクロール、マウス操作といったイベント処理は、初心者のうちはコンポーネントごとに直接書きがちですが、 数が増えるにつれて「どこで何をしているのか」が把握しづらくなります。

useEventListenerのようなカスタムフックを一つ用意しておけば、 イベントの登録や解除といった細かい処理を意識せずに使えるため、 コンポーネント側は「何をしたいか」だけを書く形になります。 これは、プログラミング未経験者がReactの考え方に慣れるうえでも大きなメリットです。


import React, { useState } from "react";
import useEventListener from "./useEventListener";

function SimpleButton() {
  const [message, setMessage] = useState("こんにちは!");

  useEventListener("click", () => {
    setMessage("ボタンがクリックされました!");
  });

  return (
    <div style={{ textAlign: "center" }}>
      <p>{message}</p>
      <button>クリック</button>
    </div>
  );
}

export default SimpleButton;
(画面に「こんにちは!」と表示され、ボタンを押すと「ボタンがクリックされました!」に変わります)

このように、イベント処理をカスタムフックに任せることで、 Reactのコードは短く、読みやすく、修正しやすい形になります。 最初は難しく感じるかもしれませんが、「同じ処理が何度も出てきたらまとめられないか」 という視点を持つことが、React上達への大切な一歩です。

まとめ

まとめ
まとめ

Reactのカスタムフックとイベントリスナーを振り返る

ここまでの記事では、Reactにおけるカスタムフックの基本から始まり、イベントリスナーを共通化する考え方や実装方法について段階的に学んできました。 React開発では、クリックやスクロール、マウス操作、キー入力といったイベント処理が頻繁に登場します。これらを各コンポーネントごとに個別に実装してしまうと、 同じようなコードが増え、可読性が下がるだけでなく、修正や保守の際にミスが発生しやすくなります。

そこで重要になるのが「カスタムフック」という考え方です。React Hooksの仕組みを活用し、共通処理をひとつの関数にまとめることで、 コンポーネントは表示や状態管理といった本来の役割に集中できるようになります。 特にイベントリスナーは、登録と解除を正しく行わないとメモリリークや意図しない動作につながるため、 カスタムフックで安全に管理する価値が非常に高い処理です。

useEventListenerフックで得られる実践的なメリット

記事内で作成したuseEventListenerフックは、イベントの種類、実行する処理、対象となる要素を引数として受け取るシンプルな構造でした。 しかし、このシンプルさこそが実務でも役立つポイントです。 スクロールイベント、クリックイベント、マウスムーブイベントなど、用途が異なっても同じフックを再利用できるため、 Reactアプリ全体の設計が統一され、コードの見通しが良くなります。

また、useEffectのクリーンアップ処理をフック内部に閉じ込めることで、 イベントリスナーの解除忘れといった初心者がつまずきやすいポイントも自然に回避できます。 このような設計は、React初心者だけでなく、中級者やチーム開発の現場でも非常に重要な考え方です。

まとめとしてのサンプル構成イメージ


function SampleComponent() {
  useEventListener("scroll", () => {
    console.log("スクロールされました");
  });

  return (
    <div className="container">
      <h2>イベントリスナー共通化のサンプル</h2>
    </div>
  );
}

このように、コンポーネント側では難しい処理を意識せず、必要なイベントを指定するだけで済む点が、 カスタムフックを使ったイベントリスナー共通化の大きな魅力です。

先生と生徒の振り返り会話

生徒:「最初はイベントリスナーって難しそうだと思っていましたが、カスタムフックにするとすごく分かりやすくなりました。」

先生:「それが狙いですね。Reactでは処理を部品として分けて考えることがとても大切です。」

生徒:「毎回useEffectを書くよりも、useEventListenerを使ったほうがミスも減りそうです。」

先生:「その通りです。イベントの登録と解除を共通化できるので、保守性も高くなります。」

生徒:「スクロールやクリック以外のイベントにも使えるのが便利ですね。」

先生:「はい。Reactのカスタムフックを理解できれば、今回のような応用はどんどん広がっていきます。」

生徒:「これからは、同じ処理を見つけたらカスタムフックにできないか考えてみます。」

先生:「それができるようになれば、React開発が一段と楽しくなりますよ。」

カテゴリの一覧へ
新着記事
New1
React
Reactコンポーネントの再利用と分割を完全マスター!初心者でもわかるコンポーネント設計
New2
React
ReactでAxiosインターセプターの使い方を完全ガイド!初心者でもわかるリクエストとレスポンスの処理方法
New3
React
JSXの書き方!初心者でもわかるReactタグと属性の基本ルール解説
New4
React
ReactとDockerを使った開発環境構築の基本を徹底解説!初心者でもわかるReactとDockerの連携方法
人気記事
No.1
Java&Spring記事人気No1
React
ReactでonChangeイベントを使ってフォーム入力値を管理する方法を初心者向けに解説
No.2
Java&Spring記事人気No2
React
ReactとTypeScriptの環境構築をやさしく解説!Viteとtsconfigの設定も丁寧に紹介
No.3
Java&Spring記事人気No3
React
Reactのイベントハンドリングのアンチパターンまとめ!初心者でもわかる注意点
No.4
Java&Spring記事人気No4
React
ReactでFetch APIのローディング状態を管理する方法|初心者にもわかる解説
No.5
Java&Spring記事人気No5
React
Reactのカスタムフックの作り方を完全ガイド!再利用可能なロジックを切り出す仕組み
No.6
Java&Spring記事人気No6
React
create-react-appでReactプロジェクトを作成する手順を初心者向けに完全解説!
No.7
Java&Spring記事人気No7
React
Reactのフォーム処理でよくあるエラーと解決法を完全解説!初心者でも安心して学べるReact入門
No.8
Java&Spring記事人気No8
React
Reactでファイルアップロードを実装する方法を解説!Fetch APIで画像やPDFを送る仕組みを初心者向けに紹介