When you want to access this
inside a class methods of your React component, you need to bind it to your method:
class Button extends Component {
constructor(props) {
super(props);
this.state = { clicked: false };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.props.setState({ clicked: true });
}
render() {
return <button onClick={this.handleClick}>Click Me!</button>;
}
}
Binding this to handleClick
in the constructor allows us to use this.setState from Component
inside handleClick
. Without this binding, this
is re-scoped for handleClick
and loses context of the component’s setState
method.
But this is completely unnecessary, extra code!
You can clean up this ugliness by using some new ES6+ features. Here is the same component, rewritten using class properties and arrow functions to avoid binding this
to handleClick
:
class Button extends Component {
state = { clicked: false };
handleClick = () => this.setState({ clicked: true });
render() {
return <button onClick={this.handleClick}>Click Me!</button>;
}
}
Note: You must have transform-class-properties enabled in your own Babel config in order to use class properties. If you’re using Create React App, this is already enabled for you.
Why Does This Work?
This works because of two reasons:
- Arrow functions, by their nature, do not re-scope
this
, so we don’t need to bindthis
in the class constructor. - JavaScript has first-class functions, meaning functions are treated the same as data. So arrow functions can be assigned to variables, or in this case, to class properties.
Bonus Tip
Notice in the second example, I defined state as a class property as well, negating the need for a constructor.
Top comments (5)
I prefer to do this:
Nice! Yes, that certainly works depending on the the use case. This approach works because
render()
is bound tothis
of the class by React.Keep in mind however that you'll have a (rather small) performance hit because the
onClick
function is being initialized every time render is invoked since that is where it is being defined.Well, I am not sure if such a thing can be called a "performance hit" since we are talking basically of 1 line of code, and there are plenty of those that run every time the render starts. The complexity of the operation is not even exponential but linear. I don't think that there is any performance concern to worry about in this case.
Enrique, I am afraid there really is a performance hit. Not because you are creating an arrow function on the fly - as you say, that's mostly irrelevant-, but because a new function will be passed as a prop and the component will re-render (needlessly).
If this happens with a button, that's not a problem, but more complex components will noticeably slow down your apps. This is a known caveat, you'll find many references in the web (for example: github.com/yannickcr/eslint-plugin...)
Also, this is based on (currently stage 2) experimental features of javascript