Detect click outside React component

后端 未结 30 1105
日久生厌
日久生厌 2020-11-22 13:54

I\'m looking for a way to detect if a click event happened outside of a component, as described in this article. jQuery closest() is used to see if the target from a click e

相关标签:
30条回答
  • 2020-11-22 14:22

    Typescript with Hooks

    Note: I'm using React version 16.3, with React.createRef. For other versions use the ref callback.

    Dropdown component:

    interface DropdownProps {
     ...
    };
    
    export const Dropdown: React.FC<DropdownProps> () {
      const ref: React.RefObject<HTMLDivElement> = React.createRef();
      
      const handleClickOutside = (event: MouseEvent) => {
        if (ref && ref !== null) {
          const cur = ref.current;
          if (cur && !cur.contains(event.target as Node)) {
            // close all dropdowns
          }
        }
      }
    
      useEffect(() => {
        // Bind the event listener
        document.addEventListener("mousedown", handleClickOutside);
        return () => {
          // Unbind the event listener on clean up
          document.removeEventListener("mousedown", handleClickOutside);
        };
      });
    
      return (
        <div ref={ref}>
            ...
        </div>
      );
    }
    
    
    0 讨论(0)
  • 2020-11-22 14:22

    I know this is an old question, but I keep coming across this and I had a lot of trouble figuring this out in a simple format. So if this would make anyones life a bit easier, use OutsideClickHandler by airbnb. It is a the simplest plugin to accomplish this task without writing your own code.

    Example:

    hideresults(){
       this.setState({show:false})
    }
    render(){
     return(
     <div><div onClick={() => this.setState({show:true})}>SHOW</div> {(this.state.show)? <OutsideClickHandler onOutsideClick={() => 
      {this.hideresults()}} > <div className="insideclick"></div> </OutsideClickHandler> :null}</div>
     )
    }
    
    0 讨论(0)
  • 2020-11-22 14:24
    componentWillMount(){
    
      document.addEventListener('mousedown', this.handleClickOutside)
    }
    
    handleClickOutside(event) {
    
      if(event.path[0].id !== 'your-button'){
         this.setState({showWhatever: false})
      }
    }
    

    Event path[0] is the last item clicked

    0 讨论(0)
  • 2020-11-22 14:27

    In my DROPDOWN case the Ben Bud's solution worked well, but I had a separate toggle button with an onClick handler. So the outside clicking logic conflicted with the button onClick toggler. Here is how I solved it by passing the button's ref as well:

    import React, { useRef, useEffect, useState } from "react";
    
    /**
     * Hook that triggers onClose when clicked outside of ref and buttonRef elements
     */
    function useOutsideClicker(ref, buttonRef, onOutsideClick) {
      useEffect(() => {
    
        function handleClickOutside(event) {
          /* clicked on the element itself */
          if (ref.current && !ref.current.contains(event.target)) {
            return;
          }
    
          /* clicked on the toggle button */
          if (buttonRef.current && !buttonRef.current.contains(event.target)) {
            return;
          }
    
          /* If it's something else, trigger onClose */
          onOutsideClick();
        }
    
        // 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 DropdownMenu(props) {
      const wrapperRef = useRef(null);
      const buttonRef = useRef(null);
      const [dropdownVisible, setDropdownVisible] = useState(false);
    
      useOutsideClicker(wrapperRef, buttonRef, closeDropdown);
    
      const toggleDropdown = () => setDropdownVisible(visible => !visible);
    
      const closeDropdown = () => setDropdownVisible(false);
    
      return (
        <div>
          <button onClick={toggleDropdown} ref={buttonRef}>Dropdown Toggler</button>
          {dropdownVisible && <div ref={wrapperRef}>{props.children}</div>}
        </div>
      );
    }
    
    0 讨论(0)
  • 2020-11-22 14:27

    Alternatively to .contains, you can use the .closest method. When you want to check if a click was outside of the element with id="apple" then i can use:

    const isOutside = !e.target.closest("#apple");
    

    This checks if any element in the tree above the clicked one has an id of "apple". We have to negate the result!

    0 讨论(0)
  • 2020-11-22 14:29

    Alternatively:

    const onClickOutsideListener = () => {
        alert("click outside")
        document.removeEventListener("click", onClickOutsideListener)
      }
    
    ...
    
    return (
      <div
        onMouseLeave={() => {
              document.addEventListener("click", onClickOutsideListener)
            }}
      >
       ...
      </div>
    
    0 讨论(0)
提交回复
热议问题