Unable to access React instance (this) inside event handler


#1

I am writing a simple component in ES6 (with BabelJS), and functions this.setState is not working.

Typical errors include something like

Cannot read property 'setState' of undefined

OR

this.setState is not a function

Code Sinppet

    import React from 'react'

    class SomeClass extends React.Component {
      constructor(props) {
        super(props)
        this.state = {inputContent: 'startValue'}
      }

      sendContent(e) {
        console.log('sending input content '+React.findDOMNode(React.refs.someref).value)
      }

      changeContent(e) {
        this.setState({inputContent: e.target.value})
      } 

      render() {
        return (
          <div>
            <h4>The input form is here:</h4>
            Title: 
            <input type="text" ref="someref" value={this.inputContent} 
              onChange={this.changeContent} /> 
            <button onClick={this.sendContent}>Submit</button>
          </div>
        )
      }
    }

    export default SomeClass

#2

Approaches to Solve this Issue

I know a total of 4 general approaches.

  1. Bind your functions in the class constructor . Considered by many as a best-practice approach that avoids touching JSX at all and doesn’t create a new function on each component re-render.
class SomeClass extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    console.log(this); // the React Component instance
  }
  render() {
    return (
      <button onClick={this.handleClick}></button>
    );
  }
}
  1. Bind your functions inline . You can still find this approach used here and there in some tutorials / articles / etc, so it’s important you’re aware of it. It it the same concept like #1, but be aware that binding a function creates a new function per each re-render.
class SomeClass extends React.Component {
  handleClick() {
    console.log(this); // the React Component instance
  }
  render() {
    return (
      <button onClick={this.handleClick.bind(this)}></button>
    );
  }
}
  1. Use a fat arrow function . Until arrow functions, every new function defined its own this value. However, the arrow function does not create its own this context, so this has the original meaning from the React component instance. Therefore, we can:
class SomeClass extends React.Component {
  handleClick() {
    console.log(this); // the React Component instance
  }
  render() {
    return (
      <button onClick={ () => this.handleClick() }></button>
    );
  }
}

or

class SomeClass extends React.Component {
  handleClick = () => {
    console.log(this); // the React Component instance
  }
  render() {
    return (
      <button onClick={this.handleClick}></button>
    );
  }
}
  1. Use utility function library to automatically bind your functions . There are a few utility libraries out there, that automatically does the job for you. Here are some of the popular, just to mention a few:
  • Autobind Decorator is an NPM package which binds methods of a class to the correct instance of this , even when the methods are detached. The package uses @autobind before methods to bind this to the correct reference to the component’s context.
import autobind from 'autobind-decorator';

class SomeClass extends React.Component {
  @autobind
  handleClick() {
    console.log(this); // the React Component instance
  }
  render() {
    return (
      <button onClick={this.handleClick}></button>
    );
  }
}

Autobind Decorator is smart enough to let us bind all methods inside a component class at once, just like approach #1.

  • Class Autobind is another NPM package that is widely used to solve this binding issue. Unlike Autobind Decorator, it does not use of the decorator pattern, but really just uses a function inside your constructor that automatically binds the Component’s methods to the correct reference of this .
import autobind from 'class-autobind';

class SomeClass extends React.Component {
  constructor() {
    autobind(this);
    // or if you want to bind only only select functions:
    // autobind(this, 'handleClick');
  }
  handleClick() {
    console.log(this); // the React Component instance
  }
  render() {
    return (
      <button onClick={this.handleClick}></button>
    );
  }
}

PS: Other very similar library is React Autobind.

Recommendation

If I were you, I would stick with approach #1. However, as soon as you get a ton of binds in your class constructor, I would recommend you to explore one of the helper libraries mentioned in approach #4.

this.changeContent needs to be bound to the component instance via this.changeContent.bind(this) before being passed as the onChange prop, otherwise the this variable in the body of the function will not refer to the component instance but to window . See Function::bind.

When using React.createClass instead of ES6 classes, every non-lifecycle method defined on a component is automatically bound to the component instance. See Autobinding.

Be aware that binding a function creates a new function. You can either bind it directly in render, which means a new function will be created every time the component renders, or bind it in your constructor, which will only fire once.

constructor() {
  this.changeContent = this.changeContent.bind(this);
}

vs

render() {
  return <input onChange={this.changeContent.bind(this)} />;
}

Refs are set on the component instance and not on React.refs : you need to change React.refs.someref to this.refs.someref . You’ll also need to bind the sendContent method to the component instance so that this refers to it.