カテゴリ: React 更新日: 2025/12/31

Reactでイベントの伝播を制御!stopPropagationの使い方を初心者向けに解説

イベントの伝播とstopPropagationの使い方
イベントの伝播とstopPropagationの使い方

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

生徒

「Reactでボタンをクリックしたときに、親要素にもクリックが伝わってしまうんですが、止める方法はありますか?」

先生

「それならstopPropagationを使います。イベントの伝播を止めるメソッドです。」

生徒

「イベントの伝播って何ですか?」

先生

「簡単に言うと、子要素で発生したイベントが親要素に順番に伝わる仕組みのことです。親子関係があるHTML要素では、クリックやマウス操作が親に伝わることがあります。」

生徒

「なるほど、では実際にReactで止める例を見たいです。」

先生

「ではコードで確認してみましょう!」

1. stopPropagationの基本的な使い方

1. stopPropagationの基本的な使い方
1. stopPropagationの基本的な使い方

Reactでは、クリックや入力などのイベントが「子要素 → 親要素」へと順番に伝わる仕組みがあります。この流れをイベントの伝播(バブリング)と呼びます。例えば、親の div と子の button の両方にクリックイベントを設定している場合、子ボタンをクリックすると親のイベントまで実行されてしまいます。意図せず複数の処理が動く原因になるため、必要に応じてevent.stopPropagation()を使って伝播を止めましょう。

下の例では、子ボタンをクリックしたときだけ反応させ、親のクリックイベントは発生しないようにしています。伝播を止める位置を理解すると、意図したとおりにUIを動かしやすくなります。


import React from "react";

function App() {
  const handleParentClick = () => {
    alert("親要素がクリックされました");
  };

  const handleChildClick = (event) => {
    event.stopPropagation(); // ここで親への伝播を止める
    alert("子要素がクリックされました");
  };

  return (
    <div 
      onClick={handleParentClick} 
      style={{ padding: "20px", border: "1px solid #000" }}
    >
      親要素
      <button 
        onClick={handleChildClick} 
        style={{ marginLeft: "10px" }}
      >
        子要素ボタン
      </button>
    </div>
  );
}

export default App;
(子要素ボタンだけが反応し、親要素のクリックアラートは表示されません)

このように、stopPropagationを使えば「どのイベントだけを実行させたいか」を明確に制御できます。フォームやモーダル、メニューなど、画面構成が複雑になるほど役に立つ重要な考え方です。

2. イベント伝播の仕組みを理解しよう

2. イベント伝播の仕組みを理解しよう
2. イベント伝播の仕組みを理解しよう

HTMLではイベントは「バブリング」という仕組みで伝わります。バブリングとは、イベントが発生した要素から親要素へ順番に伝わることです。Reactでもこの仕組みは同じで、親子のクリックイベントなどが意図せず連動することがあります。

stopPropagationを使うと、このバブリングを途中で止めることができ、子要素の処理だけを実行したい場合に便利です。フォームの中のボタンやメニュー操作などで役立ちます。

3. 応用例:複数の子要素での制御

3. 応用例:複数の子要素での制御
3. 応用例:複数の子要素での制御

複数のボタンやリンクが親要素内にある場合も、stopPropagationを使えば、特定の子要素だけイベントを止めることができます。これにより、複雑なUIでも意図した動作を実現できます。


import React from "react";

function App() {
  const handleParentClick = () => alert("親要素がクリックされました");

  const handleChildClick = (event, name) => {
    event.stopPropagation();
    alert(name + "がクリックされました");
  };

  return (
    <div onClick={handleParentClick} style={{ padding: "20px", border: "1px solid #000" }}>
      親要素
      <button onClick={(e) => handleChildClick(e, "ボタンA")} style={{ marginLeft: "10px" }}>ボタンA</button>
      <button onClick={(e) => handleChildClick(e, "ボタンB")} style={{ marginLeft: "10px" }}>ボタンB</button>
    </div>
  );
}

export default App;
(ボタンAやBをクリックしても親要素のクリックは発生せず、それぞれのボタンだけアラートが表示されます)

4. 注意点

4. 注意点
4. 注意点

stopPropagationはとても強力な道具ですが、なんとなく全部のイベントに付けてしまうと、なぜクリックイベントやフォームイベントが動かないのか分かりづらくなり、デバッグに時間がかかってしまいます。「親要素の処理まで止める必要が本当にあるか?」を毎回考えながら使うことが、Reactのイベント伝播を正しく制御するための大事なポイントです。

また、イベント関連では「伝播を止める」「ブラウザの標準動作を止める」がよく混ざってしまいます。リンクをクリックしたときに画面遷移を止めたい場合はevent.preventDefault()、親へのクリック伝播を止めたい場合はevent.stopPropagation()と、役割が違うので意識して使い分けましょう。どちらもReactのSyntheticEvent内で同じように呼び出せます。

ふたつの違いがイメージしやすいように、簡単なサンプルコードも見ておきましょう。


import React from "react";

function App() {
  const handleParentClick = () => {
    alert("親のクリックイベントが発火しました");
  };

  const handleLinkClick = (event) => {
    event.preventDefault();    // リンク先への遷移を止める
    event.stopPropagation();   // 親への伝播も止める
    alert("リンクだけの処理を実行しました");
  };

  return (
    <div
      onClick={handleParentClick}
      style={{ padding: "20px", border: "1px solid #000" }}
    >
      親要素
      <a
        href="https://example.com"
        onClick={handleLinkClick}
        style={{ marginLeft: "10px" }}
      >
        このリンクをクリック
      </a>
    </div>
  );
}

export default App;
(リンクをクリックしても画面遷移せず、親要素のクリックイベントも発生せず、リンク専用のアラートだけが表示されます)

この例のように、preventDefaultstopPropagationはセットで使われることも多いですが、「何を止めたいのか」をはっきりさせてから書くと混乱を防げます。モーダルウィンドウ内の閉じるボタン、ドロップダウンメニュー、Reactのフォームコンポーネントなど、イベントが重なりやすい場面ほど設計を丁寧に考えるとよいでしょう。

まとめると、Reactでイベント伝播を扱うときは、まず素直にクリックイベントを書いてみて、「親要素までイベントが届くと困る場所」にだけstopPropagationを追加する意識が大切です。やみくもに付けるのではなく、画面の構造とユーザーの操作を頭の中でシミュレーションしながら、必要最小限の場所に絞って使っていくと、扱いやすくシンプルなコードになります。

5. stopPropagationとイベントキャプチャの違いをおさえよう

5. stopPropagationとイベントキャプチャの違いをおさえよう
5. stopPropagationとイベントキャプチャの違いをおさえよう

Reactのイベント伝播では、よくバブリング(下から上に伝わる)だけが意識されがちですが、仕組みとしてはキャプチャ(上から下へ)という段階もあります。ふだんのonClickなどはバブリング段階で発火しますが、onClickCaptureのような「〜Capture」を使うと、親要素側で先にイベントを受け取ることができます。画面全体のクリックをまとめて監視したいときや、ログ用の処理を集約したいときなどに便利です。

ここでは、親要素でキャプチャ段階とバブリング段階の両方をログに出しつつ、子要素ではstopPropagationで親に届かないよう制御する簡単な例を見てみましょう。Reactなら、こうしたイベントの流れを少ないコードで確認できます。


import React from "react";

function App() {
  const handleCapture = () => {
    console.log("キャプチャ段階で親が反応しました");
  };

  const handleBubble = () => {
    console.log("バブリング段階で親が反応しました");
  };

  const handleChildClick = (event) => {
    event.stopPropagation();
    alert("子要素だけがクリックされました");
  };

  return (
    <div
      onClick={handleBubble}
      onClickCapture={handleCapture}
      style={{ padding: "20px", border: "1px solid #000" }}
    >
      親要素(キャプチャとバブリングをログ出力)
      <button
        onClick={handleChildClick}
        style={{ marginLeft: "10px" }}
      >
        子要素ボタン
      </button>
    </div>
  );
}

export default App;
(コンソールにはキャプチャとバブリングのログが出ますが、子要素ボタンではstopPropagationにより親のクリック処理は実行されません)

このように、イベントキャプチャとバブリングの流れを意識しながらstopPropagationを使うと、「どのタイミングでどの処理をさせるか」を細かくコントロールできます。Reactで複雑な画面を組むときほど、イベントの流れを一度図にして整理しておくと、見通しのよいコードになりやすくなります。

6. モーダルウィンドウやオーバーレイでの実践例

6. モーダルウィンドウやオーバーレイでの実践例
6. モーダルウィンドウやオーバーレイでの実践例

stopPropagationが特に役立つ場面として、モーダルウィンドウやダイアログの実装があります。よくあるパターンとして「画面のグレーアウトされた部分(オーバーレイ)をクリックするとモーダルを閉じる」「モーダルの中身をクリックしても閉じない」という動きがあります。このとき、モーダル本体のクリックイベントがオーバーレイに伝わってしまうと、意図せず閉じてしまうので、stopPropagationで親要素への伝播を止めるのが定番です。

下のコードは、オーバーレイのクリックで閉じるモーダルと、その中のコンテンツで伝播を止めるサンプルです。Reactのイベント伝播を理解していれば、こうしたよく見るUIもスムーズに実装できます。


import React, { useState } from "react";

function ModalExample() {
  const [open, setOpen] = useState(false);

  const handleOverlayClick = () => {
    setOpen(false);
  };

  const handleContentClick = (event) => {
    event.stopPropagation(); // オーバーレイへの伝播を止める
  };

  return (
    <div>
      <button onClick={() => setOpen(true)}>モーダルを開く</button>

      {open && (
        <div
          onClick={handleOverlayClick}
          style={{
            position: "fixed",
            inset: 0,
            backgroundColor: "rgba(0,0,0,0.4)",
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
          }}
        >
          <div
            onClick={handleContentClick}
            style={{
              backgroundColor: "#fff",
              padding: "20px",
              borderRadius: "8px",
              minWidth: "260px",
            }}
          >
            <h2>モーダルの中身</h2>
            <p>ここをクリックしてもモーダルは閉じません。</p>
            <button onClick={() => setOpen(false)}>閉じる</button>
          </div>
        </div>
      )}
    </div>
  );
}

export default ModalExample;
(オーバーレイ部分をクリックするとモーダルが閉じ、モーダルの白い枠内をクリックしても閉じません)

実際のWebアプリケーションでは、確認ダイアログや設定画面、画像の拡大表示など、モーダルウィンドウを使う場面がたくさんあります。そんなときにstopPropagationを正しく使えると、ユーザーが意図しないタイミングでモーダルが閉じてしまうことを防ぎ、使いやすいインターフェースを実現できます。Reactのイベント制御を練習するときは、こうしたモーダルの例を何度か手を動かして作ってみるのがおすすめです。

7. フォームやメニューで失敗しないための考え方

7. フォームやメニューで失敗しないための考え方
7. フォームやメニューで失敗しないための考え方

最後に、フォームやドロップダウンメニューなど、日常的によく使うUIでstopPropagationをどう活かすかを整理しておきましょう。入力フォームを囲む領域全体にクリックイベントを付けている場合、内部のボタンやリンクからのイベントが親に伝わると、予期せぬ送信処理や画面遷移につながることがあります。こうしたときに「どこで伝播を止めるべきか」をあらかじめ設計しておくと、後からバグに悩まされにくくなります。

例えば、カード型の一覧のどこをクリックしても詳細ページへ飛ばしたいが、「編集」ボタンだけは別の処理をしたい、という場面を考えてみましょう。カード全体にはクリック処理を持たせた上で、編集ボタン側でstopPropagationを呼ぶことで、カードへのクリックが発火しないように制御できます。


import React from "react";

function CardList() {
  const handleCardClick = (title) => {
    alert(title + "の詳細ページへ移動します");
  };

  const handleEditClick = (event, title) => {
    event.stopPropagation();
    alert(title + "を編集します");
  };

  return (
    <div>
      {["記事A", "記事B", "記事C"].map((title) => (
        <div
          key={title}
          onClick={() => handleCardClick(title)}
          style={{
            border: "1px solid #ccc",
            padding: "12px",
            marginBottom: "8px",
            cursor: "pointer",
          }}
        >
          <h3>{title}</h3>
          <p>カード全体をクリックすると詳細へ移動します。</p>
          <button
            onClick={(e) => handleEditClick(e, title)}
            style={{ marginTop: "4px" }}
          >
            編集ボタン
          </button>
        </div>
      ))}
    </div>
  );
}

export default CardList;
(カードの空いている部分をクリックすると詳細用のアラートが出て、「編集ボタン」をクリックすると編集用のアラートだけが表示されます)

フォームやメニュー、カード一覧などのUIを設計するときは、「親要素にまとめて付けたイベント」と「子要素にだけ付けたいイベント」を整理し、重なってほしくない部分にだけstopPropagationを使うと理解しやすくなります。Reactでイベントの伝播を丁寧に扱えるようになると、小さなボタン一つの動きまで思い通りにコントロールできるようになり、実務レベルのインタラクティブな画面作りにも自信がついていきます。

まとめ

まとめ
まとめ

Reactにおけるイベント伝播の仕組みと、それを制御するためのstopPropagationの使い方は、複雑なユーザーインターフェースを構築するときに非常に重要な基礎となります。特に、親子要素に複数のクリックイベントが設定されている場合、意図しない動作を避けるためにはイベントの流れを理解しながら設計することが欠かせません。今回の記事で学んだのは、子要素で実行したイベントがそのまま親要素へ「バブリング」して伝わるという構造と、それを防ぐための具体的な方法です。Reactは直感的に扱いやすい反面、細かな動作を理解していないと意図せぬイベントが発火してしまうことがあります。だからこそ、イベント伝播の制御は初心者のうちに押さえておきたいポイントです。

また、実際の現場では複数の子要素が並び、それぞれが異なる処理を担うケースが多く存在します。そのような状況でも、クリックイベントが不要に広がらないようにコントロールできるかどうかで、実装の品質や操作性が大きく変わります。とくにモーダル表示やドロップダウンメニュー・ポップアップなど、クリック領域が重なりやすいUIでは、stopPropagationを使う場面が増えます。記事で紹介したような基本構文を理解し、小さなサンプルから触れていくことで、Reactのイベント制御がぐっと身近なものになるでしょう。

ここでは、記事全体の学びを整理しつつ、応用しやすいサンプルコードをもうひとつ紹介します。親要素と複数の子要素を組み合わせ、どのタイミングで伝播を止めるのが最適なのかを体験しながら理解できる構成です。小さな例でも、イベントの動きが視覚的に確かめられることで理解が深まります。

イベント伝播の理解を深めるサンプルコード


import React from "react";

function EventSample() {
  const handleWrapperClick = () => {
    alert("全体の枠がクリックされました");
  };

  const handleBoxClick = (event) => {
    event.stopPropagation();
    alert("内側のボックスがクリックされました");
  };

  const handleButtonClick = (event) => {
    event.stopPropagation();
    alert("ボタンがクリックされました");
  };

  return (
    <div 
      onClick={handleWrapperClick} 
      style={{ padding: "20px", border: "2px solid #444", width: "260px" }}
    >
      外側の枠
      <div 
        onClick={handleBoxClick} 
        style={{ marginTop: "10px", padding: "10px", border: "1px solid #888" }}
      >
        内側のボックス
        <button 
          onClick={handleButtonClick} 
          style={{ display: "block", marginTop: "10px" }}
        >
          内側ボタン
        </button>
      </div>
    </div>
  );
}

export default EventSample;

このサンプルでは、外側の枠・内側のボックス・ボタンという三段階の親子関係が設定されています。ボタンを押したとき、伝播が止まらなければ順番にすべてのハンドラーが起動します。しかし、stopPropagationを適切な位置で使うと、意図した要素だけが反応し、他のイベントは静かに無視されます。この構造を実際に試してみると、イベントがどのように流れているかが一目で理解できるようになります。

Reactを使った開発では、動的な画面にユーザーの細かな操作が加わるため、イベント制御はあらゆるところで必要になります。とくに、クリックイベントが意図しない操作につながるとユーザー体験を損なうため、制御の知識があるかどうかで完成度が変わります。今回学んだ内容をもとに、自分のアプリや学習用プロジェクトにイベント制御を組み込んでみると、より深い理解につながるはずです。

最初は難しく見えたイベント伝播の仕組みも、小さなステップで整理していくと自然と理解が進みます。ReactのイベントはSyntheticEventという仕組みによって扱われていますが、基本の考え方は通常のDOMイベントと変わりません。この共通性を知っておくことで、他のフレームワークやネイティブJavaScriptを扱うときにも応用できます。イベントを正しく設計できるとUIの自由度が一気に高まり、複雑な操作性にも対応できるため、ぜひ積極的に実践してみましょう。

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

生徒

「イベントがどう伝わっていくのか、やっとイメージできました! ボタンから親要素に広がる仕組みなんですね。」

先生

「そうです。そして、その流れを必要に応じて止めることで意図した動きを作れるのがstopPropagationです。」

生徒

「サンプルコードを触ってみたら、どこで伝播が止まるのかがよく分かりました!」

先生

「イベント制御はUI設計の大事な部分です。身につけておくと、複雑な画面を作るときにとても役立ちますよ。」

生徒

「これでReactのイベント処理がかなり自信つきました!もっといろいろ実践してみます!」

この記事を読んだ人からの質問

この記事を読んだ人からの質問
この記事を読んだ人からの質問

プログラミング初心者からのよくある疑問/質問を解決します

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のイベントハンドリングのアンチパターンまとめ!初心者でもわかる注意点
No.3
Java&Spring記事人気No3
React
ReactとTypeScriptの環境構築をやさしく解説!Viteとtsconfigの設定も丁寧に紹介
No.4
Java&Spring記事人気No4
React
Reactのカスタムフックの作り方を完全ガイド!再利用可能なロジックを切り出す仕組み
No.5
Java&Spring記事人気No5
React
ReactでFetch APIのローディング状態を管理する方法|初心者にもわかる解説
No.6
Java&Spring記事人気No6
React
ReactのuseStateとuseEffectでよくあるエラーと解決方法ガイド!初心者でもわかるReactフック
No.7
Java&Spring記事人気No7
React
create-react-appでReactプロジェクトを作成する手順を初心者向けに完全解説!
No.8
Java&Spring記事人気No8
React
Fetch APIでPOSTリクエストを送る方法を完全解説!初心者でもわかるReactのデータ送信