1. ホーム
  2. javascript

[解決済み] Reactコンポーネント外でのクリックを検出する

2022-03-14 18:45:21

質問

以下のように、コンポーネントの外側でクリックイベントが発生したかどうかを検出する方法を探しています。 記事 jQuery closest() は、クリックイベントのターゲットが dom 要素を親の 1 つとして持っているかどうかを確認するために使用されます。一致した場合、クリックイベントは子要素に属し、コンポーネントの外部にあるとはみなされません。

そこで、私のコンポーネントでは、windowにクリックハンドラを付けたいと思います。ハンドラが起動したとき、ターゲットをコンポーネントの dom の子と比較する必要があります。

クリックイベントには "path" のようなプロパティが含まれており、イベントが移動した dom パスを保持しているようです。何を比較すればいいのか、どうすれば最適なのかが分からないので、誰かがすでに賢いユーティリティ関数にそれを入れているのではないかと思っているのですが...。ないですか?

どのように解決するのか?

React 16.3+でRefsの使い方が変わりました。

以下のソリューションはES6を使用し、バインディングのベストプラクティスに従うと同時に、メソッドを介してrefを設定します。

実際に見るには

フックの実装。

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

/**
 * Hook that alerts clicks outside of the passed ref
 */
function useOutsideAlerter(ref) {
    useEffect(() => {
        /**
         * Alert if clicked on outside of element
         */
        function handleClickOutside(event) {
            if (ref.current && !ref.current.contains(event.target)) {
                alert("You clicked outside of me!");
            }
        }

        // Bind the event listener
        document.addEventListener("mousedown", handleClickOutside);
        return () => {
            // Unbind the event listener on clean up
            document.removeEventListener("mousedown", handleClickOutside);
        };
    }, [ref]);
}

/**
 * Component that alerts if you click outside of it
 */
export default function OutsideAlerter(props) {
    const wrapperRef = useRef(null);
    useOutsideAlerter(wrapperRef);

    return <div ref={wrapperRef}>{props.children}</div>;
}

クラスの実装。

import React, { Component } from 'react';
import PropTypes from 'prop-types';

/**
 * Component that alerts if you click outside of it
 */
export default class OutsideAlerter extends Component {
    constructor(props) {
        super(props);

        this.wrapperRef = React.createRef();
        this.setWrapperRef = this.setWrapperRef.bind(this);
        this.handleClickOutside = this.handleClickOutside.bind(this);
    }

    componentDidMount() {
        document.addEventListener('mousedown', this.handleClickOutside);
    }

    componentWillUnmount() {
        document.removeEventListener('mousedown', this.handleClickOutside);
    }

    /**
     * Alert if clicked on outside of element
     */
    handleClickOutside(event) {
        if (this.wrapperRef && !this.wrapperRef.current.contains(event.target)) {
            alert('You clicked outside of me!');
        }
    }

    render() {
        return <div ref={this.wrapperRef}>{this.props.children}</div>;
    }
}

OutsideAlerter.propTypes = {
    children: PropTypes.element.isRequired,
};