カテゴリ: React 更新日: 2026/02/05

Reactでライフサイクルを利用したイベントリスナー管理を初心者向けに解説!

ライフサイクルを利用したイベントリスナー管理
ライフサイクルを利用したイベントリスナー管理

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

生徒

「Reactで画面のスクロールやウィンドウのリサイズなどのイベントを監視したいときはどうすればいいですか?」

先生

「その場合は、ライフサイクルを意識してイベントリスナーを登録・解除すると効率的です。」

生徒

「ライフサイクルを意識するってどういう意味ですか?」

先生

「コンポーネントが画面に表示されるとき、更新されるとき、消えるときのタイミングに合わせてイベントの登録や解除を行うことを指します。」

1. クラスコンポーネントでのイベントリスナー管理

1. クラスコンポーネントでのイベントリスナー管理
1. クラスコンポーネントでのイベントリスナー管理

クラスコンポーネントでは、componentDidMountでイベントリスナーを登録し、componentWillUnmountで解除するのが基本です。これにより、不要なイベントが残らず、パフォーマンスやメモリの効率が向上します。


import React from "react";

class ScrollTracker extends React.Component {
  state = { scrollY: 0 };

  handleScroll = () => {
    this.setState({ scrollY: window.scrollY });
  };

  componentDidMount() {
    window.addEventListener("scroll", this.handleScroll);
  }

  componentWillUnmount() {
    window.removeEventListener("scroll", this.handleScroll);
  }

  render() {
    return <p>スクロール位置: {this.state.scrollY}px</p>;
  }
}

export default ScrollTracker;
(コンポーネントが表示されたらスクロールを監視し、消えるときにはイベントを解除して後片付けをしています)

2. 関数コンポーネントでのイベントリスナー管理

2. 関数コンポーネントでのイベントリスナー管理
2. 関数コンポーネントでのイベントリスナー管理

関数コンポーネントでは、useEffectを使ってライフサイクルを管理します。イベントリスナーの登録と解除は、useEffect内で行い、クリーンアップ関数で解除するのがポイントです。


import React, { useState, useEffect } from "react";

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

  useEffect(() => {
    const handleScroll = () => setScrollY(window.scrollY);
    window.addEventListener("scroll", handleScroll);

    return () => {
      window.removeEventListener("scroll", handleScroll); // クリーンアップ
    };
  }, []);

  return <p>スクロール位置: {scrollY}px</p>;
}

export default ScrollTracker;
(画面表示時にスクロールイベントを監視し、コンポーネントが消えるときにクリーンアップ関数でイベントを解除しています)

3. ライフサイクルを意識したイベント管理のポイント

3. ライフサイクルを意識したイベント管理のポイント
3. ライフサイクルを意識したイベント管理のポイント

イベントリスナー管理で注意すべきポイントは以下です。

  • コンポーネントが表示されたタイミングでイベントを登録する
  • 不要になったときに必ず解除する
  • 関数コンポーネントではuseEffectのクリーンアップ関数を活用する
  • 複数のイベントを管理する場合も、登録と解除の対を揃える

これにより、メモリリークやパフォーマンスの低下を防ぎ、Reactアプリを安定して動作させることができます。

4. 実践的な応用例

4. 実践的な応用例
4. 実践的な応用例

例えば、ウィンドウのリサイズを監視して画面幅に応じたレイアウト変更を行う場合も同じです。


function WindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth);
    window.addEventListener("resize", handleResize);

    return () => {
      window.removeEventListener("resize", handleResize);
    };
  }, []);

  return <p>ウィンドウ幅: {width}px</p>;
}
(ウィンドウサイズが変わるたびに幅を更新し、コンポーネントが消えるときにイベントリスナーを解除します)

5. メリットまとめ

5. メリットまとめ
5. メリットまとめ
  • 不要なイベントが残らずメモリ消費を抑えられる
  • ライフサイクルに沿った管理でパフォーマンス向上
  • アプリが安定して動作する
  • 副作用の管理が明確になる

Reactでイベントリスナーを管理するときは、ライフサイクルやuseEffectのクリーンアップ関数を意識することが重要です。

まとめ

まとめ
まとめ

Reactにおけるライフサイクルを利用したイベントリスナー管理は、モダンなWebフロントエンド開発において避けては通れない非常に重要なトピックです。特に、スクロール、リサイズ、キー入力、マウスの動きといったブラウザ固有のイベントを扱う際には、コンポーネントが生成される「マウント時」にリスナーを登録し、破棄される「アンマウント時」に正しく解除するという一連の流れを徹底する必要があります。

もし、この解除(クリーンアップ)を忘れてしまうと、コンポーネントが画面から消えた後もバックグラウンドで処理が走り続け、動作が重くなる「メモリリーク」の原因となります。特にSPA(シングルページアプリケーション)では、ページ遷移を繰り返すうちに不要なリスナーが溜まってしまい、最終的にブラウザがクラッシュすることもあるため注意が必要です。

React Hooksによる高度なイベント制御

現代のReact開発では、クラスコンポーネントよりも useEffect フックを用いた関数コンポーネントが主流です。useEffect の第2引数に空の依存配列 [] を渡すことで、コンポーネントの初回表示時のみ実行させることができます。そして、その中で return () => { ... } という形式で関数を返すことにより、安全にクリーンアップ処理を記述できるのが大きなメリットです。

実践的な実装例:複数イベントとカスタムフック化

より実践的な現場では、複数のイベントを同時に監視したり、共通のロジックを「カスタムフック」として切り出したりすることがよくあります。以下に、マウスの座標を取得する実践的なサンプルコードを示します。


import React, { useState, useEffect } from "react";

/**
 * マウスの現在位置をリアルタイムで追跡するコンポーネント
 */
function MouseTracker() {
  const [position, setPosition] = useState({ x: 0, y: 0 });

  useEffect(() => {
    // マウス移動時のイベントハンドラ
    const handleMouseMove = (event) => {
      setPosition({
        x: event.clientX,
        y: event.clientY
      });
      console.log("マウスが動いています...");
    };

    // イベントリスナーの登録(マウント時)
    window.addEventListener("mousemove", handleMouseMove);

    // クリーンアップ関数(アンマウント時に実行)
    return () => {
      window.removeEventListener("mousemove", handleMouseMove);
      console.log("リスナーを解除しました");
    };
  }, []); // 依存配列を空にすることで1回だけ実行

  return (
    <div className="p-4 border rounded bg-light">
      <h4 className="text-primary">マウス位置の計測中</h4>
      <p>現在のX座標: <strong>{position.x}px</strong></p>
      <p>現在のY座標: <strong>{position.y}px</strong></p>
    </div>
  );
}

export default MouseTracker;
(マウスを動かすと数値がリアルタイムで更新されます。コンポーネントを切り替えて非表示にすると、コンソールに「リスナーを解除しました」と表示され、無駄な処理が止まることを確認できます)

SEOとアクセシビリティへの配慮

フロントエンドエンジニアとして意識すべきは、コードの書き方だけではありません。イベントリスナーを多用する動的なUIは、検索エンジン(Googleなど)のクローラにとっても「正しく理解できるコンテンツ」である必要があります。Reactでリサイズイベントなどを利用してレイアウトを変更する場合、CSSのメディアクエリ(Media Queries)で解決できる部分はCSSに任せ、JavaScriptが必要なインタラクションのみを useEffect で実装するという使い分けが、表示速度の改善やSEO対策において非常に有効です。

また、イベントの頻度が高い(リサイズやスクロールなど)場合は、 throttle(間引き)や debounce(遅延実行)といった技術を組み合わせて、ブラウザの負荷をさらに軽減することも検討しましょう。

エンジニアとしてのステップアップ

この記事で紹介した基礎をマスターすれば、次はカスタムフックを作成してみましょう。例えば useWindowSizeuseScrollPosition といった自作フックを作ることで、プロジェクト全体のコードの再利用性が劇的に向上します。Reactの公式ドキュメントでも推奨されている通り、ロジックと表示を切り離す設計思想を持つことが、プロ級のエンジニアへの近道となります。

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

生徒

「先生、ありがとうございました!イベントリスナーの登録だけじゃなくて、ちゃんと『後片付け』をするのがReactの鉄則なんですね。今までクリーンアップ関数を書き忘れていた気がします…。」

先生

「そうだよ。特に大規模なアプリケーションになると、その小さな『忘れ物』が積み重なって、動作がカクカクしたり、最悪の場合はブラウザが動かなくなったりするんだ。掃除をしない部屋にゴミが溜まっていくのと一緒だね。」

生徒

「なるほど、分かりやすい例えですね!useEffectの中で return を使って関数を返すだけで、勝手にコンポーネントが消える時に実行してくれるのは便利です。でも、もし依存配列(useEffectの第2引数)に変数を入れた場合はどうなるんですか?」

先生

「鋭いね!依存配列に変数を入れた場合は、その変数が更新されるたびに、まず『前の状態のクリーンアップ』が実行されてから、新しいリスナーが登録される仕組みになっているんだ。常に最新の状態を維持できるのがReactの凄いところだね。」

生徒

「つまり、変数が変わるたびに古いイベントは捨てて、新しいイベントを付け直すってことですね。これでスクロールイベントやリサイズイベントの実装にも自信がつきました!」

先生

「その意気だ。実際の開発では、Lodashのthrottleなどを使って、イベントの発火頻度を抑える工夫もあわせて学ぶと、さらにユーザーにとって使い心地の良いアプリが作れるようになるよ。次はカスタムフックの自作に挑戦してみようか!」

生徒

「はい!もっと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のカスタムフックの作り方を完全ガイド!再利用可能なロジックを切り出す仕組み
No.5
Java&Spring記事人気No5
React
ReactでFetch APIのローディング状態を管理する方法|初心者にもわかる解説
No.6
Java&Spring記事人気No6
React
create-react-appでReactプロジェクトを作成する手順を初心者向けに完全解説!
No.7
Java&Spring記事人気No7
React
ReactのuseStateとuseEffectでよくあるエラーと解決方法ガイド!初心者でもわかるReactフック
No.8
Java&Spring記事人気No8
React
Reactでファイルアップロードを実装する方法を解説!Fetch APIで画像やPDFを送る仕組みを初心者向けに紹介