saon
saon

Reputation: 741

OutSider click event using React Hook

I am trying to develop a click event handler function for the DOM element so that when I click to the outside of the div the corresponding dom element close. I have been trying the following code but I am getting the error of TypeError: node.contains is not a function. Not sure if I am doing it correctly with the react hook. Any kinds of help would be really appreciated.

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

    const OutSiderClickComponent = () => {
    const [visible, setVisible] = useState(false);
    const node = useRef();

    const handleClick = () => {
      if (!visible) {
        document.addEventListener('click', handleOutsideClick, false);
       } else {
        document.removeEventListener('click', handleOutsideClick, false);
     }
     setVisible(prevState => ({
     visible: !prevState.visible,
     }));
   }

   const handleOutsideClick = (e) => {
      if (node.contains(e.target)) {
          return;
    }
    handleClick();
    }
    return(
        <div ref={node}>
            <button onClick={handleClick}>Click to See</button>
                {visible && <div>You Clicked the Button</div>}
        </div>
       );
     };


 export default OutSiderClickComponent; 

Upvotes: 0

Views: 1943

Answers (2)

Shubham Khatri
Shubham Khatri

Reputation: 281656

There are two changes. First, you need to use node.current to check for the ref, node.current.contains(e.target) . Also the ref must be attached to the node to which you need to detect outside click

var { useState, useEffect, useRef } =  React;

    const OutSiderClickComponent = () => {
    const [visible, setVisible] = useState(false);
    const node = useRef();

    const handleClick = () => {
      if (!visible) {
        document.addEventListener('click', handleOutsideClick, false);
       } else {
        document.removeEventListener('click', handleOutsideClick, false);
     }
     setVisible(prevState => ({
     visible: !prevState.visible,
     }));
   }

   const handleOutsideClick = (e) => {
      if (node.current.contains(e.target)) {
          return;
      }
      setVisible(prev => !prev.visible)
    }
    return(
        <div>
            <button onClick={handleClick}>Click to See</button>
                {visible && <div ref={node}>You Clicked the Button</div>}
        </div>
       );
     };
     
     
ReactDOM.render(<OutSiderClickComponent />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="app" />

Upvotes: 0

r g
r g

Reputation: 3901

When you use useRef you need to remember that the value is in current attribute of ref.

Try node.current.contains().

The rest should look more like that, using React.useEffect:

const handleOutsideClick = (e) => {
    if (node.current.contains(e.target)) {
        console.log('clicked inside');
        // this.setVisible(true);
    } else {
        this.setVisible(false);
    }
}   

React.useEffect(() => {
    document.addEventListener('click', handleOutsideClick, false);
    return () => void document.removeEventListener('click', handleOutsideClick, false);
}, []);

and

<button onClick={() => void setVisible(true)}>Click to See</button>

Upvotes: 1

Related Questions