22

I am building a pulldown menu React component that should close when the user clicks anywhere in the DOM outside of the component.

Using jQuery I would typically add an event listener to the body when the pulldown is opened, and remove it again when the pulldown is closed. (The event listener itself closes the pulldown – any click events within the component are not propagated to prevent the body click handler from firing.)

Is there any way to attach a listener to the body element from within a React component? Or should I just use jQuery? (I'm a bit wary of mixing React and jQuery.)

Tim
  • 6,281
  • 3
  • 39
  • 49
  • 1
    Can't you just use the DOM? Like this: `document.body.addEventListener('click', function (evt) { // handled! })` – bmceldowney Sep 09 '15 at 17:12
  • I would try componentDidMount then inside that use comment above suggestion.Edit - what @limelights said ;) –  Sep 09 '15 at 17:14
  • Possible Duplicate : http://stackoverflow.com/questions/32553158/detect-click-outside-react-component – Vishnu Sankaran Apr 24 '17 at 05:51

2 Answers2

40

React is just JavaScript so attaching a click handler to any element is done as normal by using addEventListener(). Doing this in componentDidMount is normally very nice and tidy and clean up after yourself in componentWillUnmount by removing the added event handler.

var Component = React.createClass({
    componentDidMount: function () {
        document.body.addEventListener('click', this.myHandler);
    },
    componentWillUnmount: function () {
        document.body.removeEventListener('click', this.myHandler);
    },
    myHandler: function () {
        alert('click');
    },
    render: function() {
        return <div>Hello {this.props.name}</div>;
    }
});
Henrik Andersson
  • 45,354
  • 16
  • 98
  • 92
  • 4
    OK. Works as advertised. The only (new) problem is that stopping propagation in JS on the DOM element also prevents React events being fired in child elements, that should receive the event first. Due to React events being delegated from `document`. http://stackoverflow.com/a/24421834/698511 – Tim Sep 10 '15 at 08:19
  • 1
    Unfortunately I've noticed that this solution may indeed result in trouble depending on your use case. In order to stay within the React events realm, I'll opt for managing app state at the top level within React and the appropriate use of `shouldComponentUpdate` to avoid excessive re-rendering of unrelated components to the action. – html_programmer Jun 23 '16 at 09:26
8

It's help who used function based components:

import React, { useEffect  } from 'react';

const ZSideBar = (props) => {

    useEffect(() => {
        document.body.addEventListener('click', closeSidemenu );

        return function cleanup() {
            window.removeEventListener('click', closeSidemenu );
        } 
    },[]);
    let closeSidemenu = () => {
        document.getElementById("sidebar-tree").style.left = "-310px";
    }
   
    return (
        <div></div>
    )

}
urish
  • 8,943
  • 8
  • 54
  • 75
Jayesh Naghera
  • 319
  • 3
  • 13