0

Below is a method that is within an ES2015 class.

It cannot be an arrow function because it is an async function.

But since it is not an arrow function, "this" is not in scope so I cannot do things like setstate.

Can someone please suggest how I can get this into scope? thanks!

  async doSubmit(email_address, password) {
    this.setState({isSubmitting: true, error: null})
    try {
      let data = await this.props.app.server.doSignIn(email_address, password)
    } catch (jqXHR) {
      let errorType = (jqXHR.status >= 400 && jqXHR.status < 500) ? 'application' : 'system'
      let errorMessage = (errorType === 'application') ? jqXHR.responseJSON.description : jqXHR.error
      this.setState({error: errorMessage, isSubmitting: false})

    }
    // following a signin event make sure the user image changes
    this.props.app.reloadProfileImages()
    try {
      await this.props.app.initializeClouds()
    } catch (err) {
      xog('err', err)
      this.setState({error: errorMessage, isSubmitting: false})
    }
    this.postSignIn(data)
  }
Duke Dougal
  • 24,359
  • 31
  • 91
  • 123
  • 3
    Arrow functions can be async too. `const doSubmit = async (email_address, password) => { ... }` – CodingIntrigue Dec 05 '16 at 08:19
  • @CodingIntrigue could you please point me to some defintive reference to confirm this? Everything I have understood so far says "no async arrow functions". – Duke Dougal Dec 05 '16 at 08:27
  • 2
    Sure, here is the spec which calls out the syntax for use with an arrow: https://tc39.github.io/ecmascript-asyncawait/#prod-AsyncArrowFunction – CodingIntrigue Dec 05 '16 at 08:31
  • Could you just put `this` into a local variable? e.g. `var _this = this;` – qxz Dec 05 '16 at 08:33
  • @qxz That's difficult within a class situation because you would need to store it outside of the scope of `doStuff`, but still allow it to have access – CodingIntrigue Dec 05 '16 at 08:35
  • @CodingIntrigue Ah, right, forgot this was a method in an ES6 class. – qxz Dec 05 '16 at 08:37
  • Related: [How to access the correct `this` inside a callback?](http://stackoverflow.com/q/20279484/218196) – Felix Kling Dec 05 '16 at 14:22

2 Answers2

2

As you already use async/await ES7 feature you can also use property initializer syntax to automatically have this in scope. It's in the stage-2 Babel preset.

class Example extends React.Component {
    doSubmit = async (email_address, password) => {
        this.setState({isSubmitting: true, error: null})
        try {
          let data = await this.props.app.server.doSignIn(email_address, password)
        } catch (jqXHR) {
          let errorType = (jqXHR.status >= 400 && jqXHR.status < 500) ? 'application' : 'system'
          let errorMessage = (errorType === 'application') ? jqXHR.responseJSON.description : jqXHR.error
          this.setState({error: errorMessage, isSubmitting: false})
        }
        ...
    }

    render() {
      return (
        <button onClick={this.doSubmit("test@email.com", "password")} />
      )
    }
}
Przemysław Zalewski
  • 3,836
  • 1
  • 23
  • 23
0

You've got a few options. Firstly, arrow functions can be async, you just need to attach it to a property of the class:

constructor() {
    this.doSubmit = async (email_address, password) => {

    };
}

Here's an example of that working in the Babel REPL.

If you want to keep the class declaration the way it is, you can use bind within the constructor to ensure the this reference is always bound to the class instance:

constructor() {
    this.doSubmit = this.doSubmit.bind(this);
}

async doSubmit(email_address, password) {
    ...
}
CodingIntrigue
  • 75,930
  • 30
  • 170
  • 176