イベントキャプチャとバブリング


次のコードを想像してみてください.
  const [counter, setCounter] = useState(0);
  return (
    <div onClick={() => setCounter((prevCounter) => prevCounter + 1)}>
      <button onClick={() => setCounter((prevCounter) => prevCounter + 1)}>
        Counter value is: {counter}
      </button>
    </div>
  );
このボタンをレンダリングします

あなたがそれをクリックすると、そのボタンに何が表示されますか?
あなたは“カウンター値は:1”と推測した場合は、間違っていた!
私たちが得るのはこれです.

でもどうして?

イベント伝播の理解


我々の例では、我々はbutton , そのイベントハンドラdiv 親もトリガされました.なぜなら、イベントは、DOMツリーを通って上下に移動するイベントを生成したターゲット要素に影響を与えないからです.
これはイベント伝播として知られています:イベントがどのように伝播するか、DOM木を通って進むかを定義するメカニズムはその目標に到着します、そして、その後、それは起こります.
イベント伝播の概念は、親子関係のDOM階層の複数の要素が同じイベント(例えばマウスクリック)のイベントハンドラを持っている状況に対処するために導入されました.ここで、ユーザーが内部要素をクリックしたときに最初に要素のClickイベントがどのように処理されるのかを説明します.外側の要素のクリックイベント、または内側の要素をクリックします.
イベント伝搬には3つのフェーズがあります.
  • フェーズをキャプチャ-イベントはwindow まで達するevent.target .
  • ターゲットフェイズ-イベントはevent.target . イベントを引き起こした最も深くネストされた要素は、ターゲット要素と呼ばれ、event.target .
  • バブリングフェイズ-泡からのイベント泡event.target までの要素をwindow , 意味:イベントが要素の上で起こるとき、それは最初にそれの上でハンドラーを実行します、そして、それから親で、それから、他の祖先の上のすべての方法.それはキャプチャフェーズで起こっていることの逆です.

  • イベントバブルと反応でキャプチャ


    バブリングとキャプチャの両方は、DOM仕様によって説明された方法と同じ方法でサポートされています.
    バブリングは、通常のDOM APIと同様に簡単です単に要素の最終的な親にハンドラを付けてください、そして、その要素の上で引き起こされるどんなイベントも最初に我々の例のように、親に泡立つでしょう.
    キャプチャと同じように簡単ですが、代わりにonClick propを使用する必要がありますonClickCapture あなたの要素で.

    どのようにバブリング/キャプチャからイベントを停止するのですか?


    私たちの元の例に戻って、どのように我々は我々がボタンをクリックするときに我々のカウンタが1だけ増加されることを確認することができますか?
    答えは使用ですstopPropagation()このメソッドEvent インターフェースは、キャプチャおよびバブリング段階における現在のイベントのさらなる伝播を防止する.
    しかしながら、どんなデフォルト動作も起こらないようにしません.(これらの動作を停止したい場合は、preventDefault() 方法)
    コードを次のように変更すると、
      const [counter, setCounter] = useState(0);
      return (
        <div onClick={() => setCounter((prevCounter) => prevCounter + 1)}>
          <button
            onClick={(event) => {
              event.stopPropagation();
              setCounter((prevCounter) => {
                return prevCounter + 1;
              });
            }}
          >
            Counter value is: {counter}
          </button>
        </div>
    
    我々のカウンタは、我々がボタンをクリックするたびに、1によって増分されますevent.stopPropagation() これにより、イベントがbutton 's親と親のトリガonClick 同様に.
    しかし、時々、あなたは、あなたが要素の両親のうちの1つのイベントを必要としないことを本当に確信することができないので、伝播からイベントを止めるとき、注意してください.
    これがケースであるならば、伝播を止める1つの代替はあなたのデータを1つのハンドラーのイベントオブジェクトに書いて、もう一つのものでそれを読んでいます.
    ハッピーコーディング!🚀