Most of the time, your components respond to events that occur within the component tree by defining their own handler or by accepting a handler defined by a parent component via props. Sometimes, this isn't enough. In this lesson, we'll rely on lifecycle hooks and good old fashioned DOM events to update state in a React component in response to an event that occurs outside of the component tree.

 

class Menu extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      isVisible: false
    }
    this.handleClickOutside = this.handleClickOutside.bind(this)
    this.toggleOptions = this.toggleOptions.bind(this)
    this.handleClick = this.handleClick.bind(this)
  }
  componentDidMount() {
    document.addEventListener('click', this.handleClickOutside)
  }

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

  handleClickOutside(evt) {
    if (!this.node.contains(evt.target)) {
      this.setState({ isVisible: false })
    }
  }

  toggleOptions(evt) {
    evt.preventDefault()
    this.setState(state => ({ isVisible: !state.isVisible }))
  }

  handleClick(choice, evt) {
    evt.preventDefault()
    this.props.handleMenuChoice(choice)
    this.setState({ isVisible: false })
  }

  render() {
    return (
      
    )
  }
}

 

The most important thing is how to detect whether user click outside the menu or not.

To do that, we use 'ref':

ref={el => (this.node = el)}>

We assign the elememt to vairable 'this.node'.

 

console log the node:

 

When we click inside the menu, the 'evt.target' is the 'a' tag.

If we click outside the menu, then then 'evt.target' is the whole html tag.

Therefore, we can check:

if (!this.node.contains(evt.target)) {