Reputation: 1238
I am struggling to understand how this
works within ES6 classes which makes it hard to build applications with any kind of consistency. Here is one example of my confusion within a React class:
class Class extends React.Component {
constructor() {
super();
this.state = {
timeout: 0
}
}
componentWillMount() {
// Register with Flux store.
// On change run this._storeUpdated()
}
_storeUpdated() {
if (this.state.timeout < 3) {
console.log(this.state.timeout); // 0
setTimeout(() => {
this.setState({
authorized: false,
timeout: this.state.timeout + 1 // undefined?
});
// Force Flux store to update - re-runs this method.
}, 1000)
}
}
}
Why is this.state.timeout undefined
within the call to setState()
? However if I arrow function the method then it works:
_storeUpdated = () => {
if (this.state.timeout < 3) {
console.log(this.state.timeout); // 0
setTimeout(() => {
this.setState({
authorized: false,
timeout: this.state.timeout + 1 // 1
});
// Force Flux store to update - re-runs this method.
}, 1000)
}
}
What is actually going on here?
Upvotes: 1
Views: 1292
Reputation: 4979
You might be confused because React does autobinding when using React.createClass
, but it does not when inheriting from React.Component
(i.e. the ES6 way). This change was explained in the 0.13 beta1 blog post.
In your specific case, and since you are using Flux.getStore('store').on('change', this._storeUpdated);
, (which is a method on EventEmitter3, as used by Flummox) the context is set to the EventEmitter
object, which has nothing to do with your component object and has no state
attribute.
Note you can specify the value of this
as the third argument when registering the event listener: Flux.getStore('store').on('change', this._storeUpdated, <this-object>);
For achieving autobind in ES6 classes, you should use any of the methods described in the React blog post. As a side note, and if you are into ES7, you can even use an autobind decorator.
Upvotes: 3