Sebastian Olsen Sebastian Olsen - 3 months ago 6
Javascript Question

this.setState() not working properly with bound events

I'm making an easily toggleable component, here I've made a door as an example. You click the door and it opens, if you click on it again, it closes. If you click outside of the door, it will close as well.

My issue here is that in the

handleClick()
method, the
state.active
is always
false
, no matter what. Even after I set the state, it returns false when I
console.log
it. The actual
door
does get the
"active"
class assigned to it though, so why does the method not see the change?

export default class Door extends React.Component {
constructor() {
super()
this.state = {
active: false,
}

this.close = this.close.bind(this)
this.open = this.open.bind(this)
}

handleClick() {
if (this.state.active == false) {
this.open()
} else {
this.close()
}
}

open() {
document.body.addEventListener('click', this.close, true)
this.setState({active: true})
}

close() {
document.body.removeEventListener('click', this.close, true)
this.setState({active: false})
}

render() {

let classes = {
active: this.state.active ? 'active ' : '',
}

return (
<div onClick={this.handleClick.bind(this)} className={"door " + classes.active}>
</div>
)
}
}

Answer

You should stop propagation:

handleClick(e) {
    e.stopPropagation();
    if (this.state.active == false) {
      this.open()
    } else {
      this.close()
    }
  }

When you are trying to close the door, the handleClick is called twice. once by the div click, and then by the body click. This can be avoided by stopping the event from bubbling up when handled once.