jamie holliday
jamie holliday

Reputation: 1627

Value of this in React event handler

For some reason the value of this is being lost in react event handler. Reading the docs I thought that react did some stuff here to make sure this was set to the correct value

The following doesn't work as I'd expect

import React from 'react';

export default class Observer extends React.Component {

    handleClick() {
        console.log(this); //logs undefined
    }
    render() {
        return (
            <button onClick={this.handleClick}>Click</button>
        );
    }
}

But this does:

import React from 'react';

export default class Observer extends React.Component {

    handleClick() {
        console.log(this); //logs Observer class instance
    }
    render() {
        return (
            <button onClick={this.handleClick.bind(this)}>Click</button>
        );
    }
}

React and ES6 is new to me but this seems to not be the correct behaviour?

Upvotes: 26

Views: 19884

Answers (3)

Aaron Beall
Aaron Beall

Reputation: 52133

The accepted answer is good and I've used it a lot in ES6, but I just want to add another "more modern" solution we have with ES7 (mentioned in the React component class auto-binding notes): use arrow functions as class properties, then you don't need to bind or wrap your handler anywhere.

export default class Observer extends React.Component {
  handleClick = (e) => {
    /* ... */
  }
  render() {
      return <button onClick={this.handleClick}>Click</button>
  }
}

This is the simplest and cleanest solution yet!

Upvotes: 15

Anders Ekdahl
Anders Ekdahl

Reputation: 22933

Like others have said, React doesn't autobind methods to the instance when using ES6 classes. That said, I would make habit of always using arrow functions in event handlers like: onClick={e => this.handleClick()}

Instead of: onClick={this.handleClick.bind(this)}

This because it means that you can replace the handleClick method with a spy in a test, something you can't do when you use bind.

Upvotes: 11

WiredPrairie
WiredPrairie

Reputation: 59763

This is correct behavior for JavaScript and React if you use the new class syntax.

The autobinding feature does not apply to ES6 classes in v0.13.0.

So you'll need to use:

 <button onClick={this.handleClick.bind(this)}>Click</button>

Or one of the other tricks:

export default class Observer extends React.Component {
  constructor() {
    super();
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    /* ... */
  }
  render() {
      return <button onClick={this.handleClick}>Click</button>
  }
}

Upvotes: 35

Related Questions