【ReactJS】コンポーネント外部のクリックイベントを検知する方法 3選
ReactJS でコンポーネント外部のクリックイベントを検知する方法
以下の3つの方法で、コンポーネント外部のクリックイベントを検知できます。
useRef フックと useEffect フックを使用する
この方法は、DOM 要素を参照し、その要素にイベントリスナーを登録することで実現します。
import React, { useState, useEffect, useRef } from 'react';
const MyComponent = () => {
const [isClickedOutside, setIsClickedOutside] = useState(false);
const ref = useRef(null);
useEffect(() => {
const handleClickOutside = (event) => {
if (ref.current && !ref.current.contains(event.target)) {
setIsClickedOutside(true);
}
};
document.addEventListener('click', handleClickOutside);
return () => {
document.removeEventListener('click', handleClickOutside);
};
}, []);
return (
<div ref={ref}>
<div>コンポーネント内</div>
{isClickedOutside && <div>コンポーネント外がクリックされました</div>}
</div>
);
};
export default MyComponent;
ReactDOM.createPortal を使用する
この方法は、ポータルを使用してコンポーネントを DOM の別の場所にレンダリングすることで実現します。
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
const MyComponent = () => {
const [isClickedOutside, setIsClickedOutside] = useState(false);
const handleClickOutside = (event) => {
setIsClickedOutside(true);
};
return (
<div>
<div>コンポーネント内</div>
{isClickedOutside && ReactDOM.createPortal(<div>コンポーネント外がクリックされました</div>, document.body)}
</div>
);
};
export default MyComponent;
react-outside-click-handler ライブラリを使用する
この方法は、ライブラリを使用してコンポーネント外部のクリックイベント検知を簡略化できます。
import React from 'react';
import OutsideClickHandler from 'react-outside-click-handler';
const MyComponent = () => {
const handleOutsideClick = () => {
console.log('コンポーネント外がクリックされました');
};
return (
<OutsideClickHandler onOutsideClick={handleOutsideClick}>
<div>コンポーネント内</div>
</OutsideClickHandler>
);
};
export default MyComponent;
これらの方法の中から、状況に合った方法を選択してください。
react-outside-click-handler
ライブラリを使用する場合は、ライブラリのドキュメントを参照してください。ReactDOM.createPortal
を使用する場合、ポータルをレンダリングする要素は、コンポーネントと同じ親要素である必要があります。- 上記の例では、コンポーネント内をクリックしても
isClickedOutside
が true になるのを防ぐために、ref.current.contains(event.target)
を使用しています。
import React, { useState, useEffect, useRef } from 'react';
const MyComponent = () => {
const [isClickedOutside, setIsClickedOutside] = useState(false);
const ref = useRef(null);
useEffect(() => {
const handleClickOutside = (event) => {
if (ref.current && !ref.current.contains(event.target)) {
setIsClickedOutside(true);
}
};
document.addEventListener('click', handleClickOutside);
return () => {
document.removeEventListener('click', handleClickOutside);
};
}, []);
return (
<div ref={ref}>
<div>コンポーネント内</div>
{isClickedOutside && <div>コンポーネント外がクリックされました</div>}
</div>
);
};
export default MyComponent;
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
const MyComponent = () => {
const [isClickedOutside, setIsClickedOutside] = useState(false);
const handleClickOutside = (event) => {
setIsClickedOutside(true);
};
return (
<div>
<div>コンポーネント内</div>
{isClickedOutside && ReactDOM.createPortal(<div>コンポーネント外がクリックされました</div>, document.body)}
</div>
);
};
export default MyComponent;
import React from 'react';
import OutsideClickHandler from 'react-outside-click-handler';
const MyComponent = () => {
const handleOutsideClick = () => {
console.log('コンポーネント外がクリックされました');
};
return (
<OutsideClickHandler onOutsideClick={handleOutsideClick}>
<div>コンポーネント内</div>
</OutsideClickHandler>
);
};
export default MyComponent;
説明
この例では、useRef
フックを使用してコンポーネント要素を参照し、useEffect
フックを使用してイベントリスナーを登録しています。イベントリスナーは、document
オブジェクトの click
イベントに登録されます。イベントがトリガーされると、handleClickOutside
関数が呼び出されます。この関数は、クリックされた要素がコンポーネント要素内にあるかどうかを確認します。もしそうでなければ、isClickedOutside
state 変数を true に設定します。
この例では、ReactDOM.createPortal
関数を使用してコンポーネントを document.body
にレンダリングしています。これにより、コンポーネントは DOM ツリー内の別の場所に配置され、コンポーネント外部のクリックイベントを検知することができます。handleClickOutside
関数は、コンポーネント外部がクリックされたときに呼び出されます。
Context API を使用して、コンポーネントツリー全体にクリックされた状態を共有することができます。
import React, { useState, createContext } from 'react';
const ClickedOutsideContext = createContext(false);
const ClickedOutsideProvider = ({ children }) => {
const [isClickedOutside, setIsClickedOutside] = useState(false);
const handleClickOutside = (event) => {
setIsClickedOutside(true);
};
useEffect(() => {
document.addEventListener('click', handleClickOutside);
return () => document.removeEventListener('click', handleClickOutside);
}, []);
return (
<ClickedOutsideContext.Provider value={isClickedOutside}>
{children}
</ClickedOutsideContext.Provider>
);
};
const MyComponent = () => {
const isClickedOutside = useContext(ClickedOutsideContext);
return (
<div>
<div>コンポーネント内</div>
{isClickedOutside && <div>コンポーネント外がクリックされました</div>}
</div>
);
};
export default function App() {
return (
<ClickedOutsideProvider>
<MyComponent />
</ClickedOutsideProvider>
);
}
カスタムフックを使用する
カスタムフックを使用して、コンポーネント外部のクリックイベント検知ロジックを再利用することができます。
import React, { useState, useRef, useEffect } from 'react';
const useClickOutside = (ref) => {
const [isClickedOutside, setIsClickedOutside] = useState(false);
useEffect(() => {
const handleClickOutside = (event) => {
if (ref.current && !ref.current.contains(event.target)) {
setIsClickedOutside(true);
}
};
document.addEventListener('click', handleClickOutside);
return () => document.removeEventListener('click', handleClickOutside);
}, [ref]);
return isClickedOutside;
};
const MyComponent = () => {
const ref = useRef(null);
const isClickedOutside = useClickOutside(ref);
return (
<div ref={ref}>
<div>コンポーネント内</div>
{isClickedOutside && <div>コンポーネント外がクリックされました</div>}
</div>
);
};
export default MyComponent;
Higher-Order Component (HOC) を使用する
HOCを使用して、コンポーネント外部のクリックイベント検知ロジックをコンポーネントにラップすることができます。
import React from 'react';
const withClickOutsideDetection = (Component) => {
const ClickOutsideComponent = (props) => {
const ref = useRef(null);
const [isClickedOutside, setIsClickedOutside] = useState(false);
useEffect(() => {
const handleClickOutside = (event) => {
if (ref.current && !ref.current.contains(event.target)) {
setIsClickedOutside(true);
}
};
document.addEventListener('click', handleClickOutside);
return () => document.removeEventListener('click', handleClickOutside);
}, [ref]);
return (
<div ref={ref}>
<Component {...props} isClickedOutside={isClickedOutside} />
</div>
);
};
return ClickOutsideComponent;
};
const MyComponent = ({ isClickedOutside }) => {
return (
<div>
<div>コンポーネント内</div>
{isClickedOutside && <div>コンポーネント外がクリックされました</div>}
</div>
);
};
const ClickOutsideMyComponent = withClickOutsideDetection(MyComponent);
export default ClickOutsideMyComponent;
これらの方法は、状況に応じて使い分けることができます。
注意事項
- パフォーマンスを向上させるために、イベントリスナーをコンポーネントのマウント時とアンマウント時に登録するようにしてください。
- 上記の方法はすべて、コンポーネントの外部で発生する クリックイベントのみ を検知します。他のタイプのイベント (例: キーボードイベント、マウスホイールイベント) を検知したい場合は、別の方法を使用する必要があります。
reactjs