1

In my React app, I am trying to call this.setState() within the body of a new Promise - however, this is undefined in the body of the Promise.

The function is in a module called ui.js:

export const toggleButtonsDisabled = function(buttonsAreDisabled) {
    return new Promise(function(resolve) {
        this.setState({"buttonsDisabled": !buttonsAreDisabled}, () => {
            resolve()
        })
    })
}

And it is referenced in a component like so:

import { toggleButtonsDisabled } from "../../scripts/ui"

class Test extends Component {
    constructor() {
        this.toggleButtonsDisabled = toggleButtonsDisabled.bind(this)
        this.handleSubmit = this.handleSubmit.bind(this)
        this.state = {
            "buttonsDisabled": false
        }
    }

    handleSubmit() {
        this.toggleButtonsDisabled(this.state.buttonsDisabled)
            .then(function() {
                // DO SOME STUFF...
            })
    }

    // FORM, ETC...
}

If handleSubmit() is called, an error comes back saying cannot read property 'setState' of undefined - the reference to this is lost in the scope of the Promise.

If I rewrite the function as:

export const toggleButtonsDisabled = function(buttonsAreDisabled) {
    const reactComponent = this

    return new Promise(function(resolve) {
        reactComponent.setState({"buttonsDisabled": !buttonsAreDisabled}, () => {
            resolve()
        })
    })
}

then it works, no problem... but is there a more elegant way to handle this? Or am I asking for the impossible?

skwidbreth
  • 7,888
  • 11
  • 58
  • 105

1 Answers1

1

One of the interesting qualities of arrow functions is that they do not have their own this so they look at the local lexical environment for one.

You can solve your issue of having to assign this to a new variable by using an arrow function:

return new Promise(resolve => {
  this.setState({"buttonsDisabled": !buttonsAreDisabled}, () => {
    resolve();
  });
});
Andy
  • 61,948
  • 13
  • 68
  • 95