Julien Vincent
Julien Vincent

Reputation: 1238

The scope of `this` in ES6 classes

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

Answers (1)

julen
julen

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

Related Questions