ReactJS ネストされたコンポーネントのクリックイベント伝播を阻止する方法
ReactJSでネストされたコンポーネントのクリックイベント伝播を阻止する方法
イベント伝播は、イベントが発生した要素から親要素へと順に伝達していく仕組みです。多くの場合、これは望ましい動作ですが、場合によっては意図せず親要素のイベントが発火してしまうことがあります。
例えば、以下のようなコードを考えてみましょう。
const App = () => {
const handleClick = () => {
console.log('親要素のクリックイベント');
};
return (
<div onClick={handleClick}>
<button onClick={() => console.log('子要素のクリックイベント')}>ボタン</button>
</div>
);
};
このコードでは、親要素と子要素それぞれに onClick
イベントハンドラが設定されています。子要素のボタンをクリックすると、以下の2つのイベントが順番に発火します。
- 子要素の
onClick
イベント
これは、子要素のクリックイベントが親要素にも伝播してしまうためです。
イベント伝播を阻止するには、以下の方法があります。
e.stopPropagation()
メソッドを使用すると、イベントの伝播を止めることができます。
const App = () => {
const handleClick = () => {
console.log('親要素のクリックイベント');
};
const handleClickChild = (e) => {
console.log('子要素のクリックイベント');
e.stopPropagation();
};
return (
<div onClick={handleClick}>
<button onClick={handleClickChild}>ボタン</button>
</div>
);
};
上記のコードでは、子要素の onClick
イベントハンドラ内で e.stopPropagation()
メソッドを呼び出すことで、イベント伝播を阻止しています。
stopImmediatePropagation()
メソッドは、stopPropagation()
メソッドと似ていますが、イベント伝播を現在のイベントハンドラだけでなく、その後のイベントハンドラにも伝播させないことができます。
const App = () => {
const handleClick = () => {
console.log('親要素のクリックイベント');
};
const handleClickChild = (e) => {
console.log('子要素のクリックイベント');
e.stopImmediatePropagation();
};
return (
<div onClick={handleClick}>
<button onClick={handleClickChild}>ボタン</button>
</div>
);
};
上記のコードでは、子要素の onClick
イベントハンドラ内で e.stopImmediatePropagation()
メソッドを呼び出すことで、イベント伝播を現在のイベントハンドラだけでなく、親要素の onClick
イベントハンドラにも伝播させないようにしています。
イベントハンドラをpreventDefaultでキャンセルする
preventDefault
メソッドを使用すると、イベントのデフォルト動作をキャンセルすることができます。
const App = () => {
const handleClick = (e) => {
e.preventDefault();
console.log('親要素のクリックイベント');
};
const handleClickChild = (e) => {
console.log('子要素のクリックイベント');
};
return (
<div onClick={handleClick}>
<a href="#">リンク</a>
<button onClick={handleClickChild}>ボタン</button>
</div>
);
};
イベント伝播は便利な仕組みですが、場合によっては意図せず親要素のイベントが発火してしまうことがあります。イベント伝播を阻止するには、e.stopPropagation()
メソッドや e.stopImmediatePropagation()
メソッド、preventDefault
メソッドを使用することができます。
どの方法を使用するかは、状況によって異なります。それぞれの方法のメリットとデメリットを理解して、適切な方法を選択しましょう。
補足
イベント伝播を阻止するサンプルコード
const App = () => {
const handleClick = () => {
console.log('親要素のクリックイベント');
};
const handleClickChild = (e) => {
console.log('子要素のクリックイベント');
// イベント伝播を阻止
e.stopPropagation();
};
return (
<div onClick={handleClick}>
<button onClick={handleClickChild}>ボタン</button>
</div>
);
};
イベント伝播をキャンセルするサンプルコード
const App = () => {
const handleClick = (e) => {
// イベントのデフォルト動作をキャンセル
e.preventDefault();
console.log('親要素のクリックイベント');
};
const handleClickChild = (e) => {
console.log('子要素のクリックイベント');
};
return (
<div onClick={handleClick}>
<a href="#">リンク</a>
<button onClick={handleClickChild}>ボタン</button>
</div>
);
};
- イベント伝播を利用して、親要素の状態を変更するサンプルコード
- イベント伝播を利用して、複数のコンポーネント間で通信を行うサンプルコード
これらのサンプルコードは、以下のサイトで紹介されています。
イベント伝播を阻止する他の方法
event.target を使用して、イベント発生要素を取得する
const App = () => {
const handleClick = (e) => {
// イベント発生要素を取得
const target = e.target;
// イベント発生要素が子要素であれば、イベント伝播を阻止
if (target.tagName === 'BUTTON') {
e.stopPropagation();
}
};
return (
<div onClick={handleClick}>
<button>ボタン</button>
</div>
);
};
上記のコードでは、event.target
プロパティを使用して、イベント発生要素を取得しています。イベント発生要素が子要素であれば、e.stopPropagation()
メソッドを呼び出すことで、イベント伝播を阻止しています。
ref を使用して、子要素のDOM要素を取得する
ref
を使用すると、コンポーネント内で子要素のDOM要素を取得することができます。
const App = () => {
const buttonRef = useRef();
const handleClick = (e) => {
// 子要素のDOM要素を取得
const button = buttonRef.current;
// 子要素のDOM要素をクリックしている場合は、イベント伝播を阻止
if (button === e.target) {
e.stopPropagation();
}
};
return (
<div onClick={handleClick}>
<button ref={buttonRef}>ボタン</button>
</div>
);
};
getDerivedStateFromProps
は、親コンポーネントの props が更新された際に呼び出されるライフサイクルメソッドです。
const App = () => {
const [isClicked, setIsClicked] = useState(false);
const handleClick = (e) => {
// 子要素がクリックされたことを親コンポーネントに伝える
setIsClicked(true);
};
const getDerivedStateFromProps = (nextProps) => {
// 親コンポーネントの props が更新された場合、イベント伝播を阻止
if (nextProps.isClicked) {
e.stopPropagation();
}
return null;
};
return (
<div onClick={handleClick}>
<button>ボタン</button>
</div>
);
};
上記のコードでは、getDerivedStateFromProps
を使用して、親コンポーネントの props が更新された際にイベント伝播を阻止しています。
reactjs onclick event-propagation