charlieanstey
11/14/2017 - 9:28 AM

React, removeEventListener and bind(this) gotcha

React, removeEventListener and bind(this) gotcha

/*  Sometimes it's pretty easy to run ito troubles with React ES6 components.
    Consider the following code: */

class EventStub extends Component {
  componentDidMount() {
    window.addEventListener('resize', this.onResize.bind(this)); //notice .bind
  }
  
  componentWillUnmount() {
    window.removeEventListener('resize', this.onResize.bind(this));
  }
  
  onResize() {
    this.setState({width: this.div.offsetWidth});
  }
  
  render() { return null; }
}

/*  As a result EventListener won't be removed since A new function reference is created after .bind() is called. 
(more http://stackoverflow.com/questions/11565471/removing-event-listener-which-was-added-with-bind 
and http://alexfedoseev.com/post/65/react-event-handlers-and-context-binding). 
Obviously this is not React's fault, it's how DOM works, but it's super easy to make a mistake. ESLint rule anyone?

What about solutions? Pretty straightforward one is to create bound funciton only once in constructor,
assign to internal prop and then use it:*/
this.bound_onResize = this.onResize(bind);

//or replace the funtion with the bound one that allows to use same funtion: 
this.onResize = this.onResize.bind(this);

//another options is to use arrow funciton on a class level so it'll capture "this" automatically, 
//but this is as of Jan 2016 Stage 2 ES2016 (ES7) proposal and requires "babel experimental" flag
export class MyComponent extends Component { 
    onResize = () => this.onResize()
}