检测点击外部组件反应钩

pet*_*gan 4 javascript ecmascript-6 reactjs

我正在尝试使用react挂钩来确定用户是否在元素外部单击。我useRef用来获取对该元素的引用。

谁能看到解决方法。我从这里得到以下错误和答案

属性“包含”在类型“ RefObject”上不存在

上面的错误似乎是打字稿问题。

这里有一个带有不同错误的代码沙箱

在这两种情况下,它都不起作用。

import React, { useState, useEffect, useRef } from 'react';
import ReactDOM from 'react-dom';

const Menu = () => {
    const wrapperRef = useRef<HTMLDivElement>(null);
    const [isVisible, setIsVisible] = useState(true);

    // below is the same as componentDidMount and componentDidUnmount
    useEffect(() => {
        document.addEventListener('click', handleClickOutside, true);
        return () => {
            document.removeEventListener('click', handleClickOutside, true);
        };
    }, []);


    const handleClickOutside = event => {
       const domNode = ReactDOM.findDOMNode(wrapperRef);
       // error is coming from below
       if (!domNode || !domNode.contains(event.target)) {
          setIsVisible(false);
       }
    }

    return(
       <div ref={wrapperRef}>
         <p>Menu</p>
       </div>
    )
}
Run Code Online (Sandbox Code Playgroud)

the*_*ude 9

useRef API应该使用这样的:

import React, { useState, useRef, useEffect } from "react";
import ReactDOM from "react-dom";

function App() {
  const wrapperRef = useRef(null);
  const [isVisible, setIsVisible] = useState(true);

  // below is the same as componentDidMount and componentDidUnmount
  useEffect(() => {
    document.addEventListener("click", handleClickOutside, false);
    return () => {
      document.removeEventListener("click", handleClickOutside, false);
    };
  }, []);

  const handleClickOutside = event => {
    if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
      setIsVisible(false);
    }
  };

  return (
    isVisible && (
      <div className="menu" ref={wrapperRef}>
        <p>Menu</p>
      </div>
    )
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Run Code Online (Sandbox Code Playgroud)


pra*_*nde 5

我创建了这个通用钩子,它可用于所有需要此功能的 div。

import { useEffect } from 'react';

/**
 *
 * @param {*} ref - Ref of your parent div
 * @param {*} callback - Callback which can be used to change your maintained state in your component
 * @author Pranav Shinde 30-Nov-2021
 */
const useOutsideClick = (ref, callback) => {
    useEffect(() => {
        const handleClickOutside = (evt) => {
            if (ref.current && !ref.current.contains(evt.target)) {
                callback(); //Do what you want to handle in the callback
            }
        };
        document.addEventListener('mousedown', handleClickOutside);
        return () => {
            document.removeEventListener('mousedown', handleClickOutside);
        };
    });
};

export default useOutsideClick;
Run Code Online (Sandbox Code Playgroud)

用法 -

  1. 在您的组件中导入钩子
  2. 添加一个 ref 到你的包装 div 并将其传递给钩子
  3. 添加回调函数来更改您的状态(隐藏下拉菜单/模式)
import React, { useRef } from 'react';
import useOutsideClick from '../../../../hooks/useOutsideClick';

const ImpactDropDown = ({ setimpactDropDown }) => {
    const impactRef = useRef();

    useOutsideClick(impactRef, () => setimpactDropDown(false)); //Change my dropdown state to close when clicked outside

    return (
        <div ref={impactRef} className="wrapper">
            {/* Your Dropdown or Modal */}
        </div>
    );
};

export default ImpactDropDown;

Run Code Online (Sandbox Code Playgroud)