Is using async componentDidMount() good?

Mirakurun picture Mirakurun · Dec 25, 2017 · Viewed 79.4k times · Source

Is using componentDidMount() as an async function good practice in React Native or should I avoid it?

I need to get some info from AsyncStorage when the component mounts, but the only way I know to make that possible is to make the componentDidMount() function async.

async componentDidMount() {
    let auth = await this.getAuth();
    if (auth) 
        this.checkAuth(auth);
}

Is there any problem with that and are there any other solutions to this problem?

Answer

Cù Đức Hiếu picture Cù Đức Hiếu · Dec 25, 2017

Let's start by pointing out the differences and determining how it could cause troubles.

Here is the code of async and "sync" componentDidMount() life-cycle method:

// This is typescript code
componentDidMount(): void { /* do something */ }

async componentDidMount(): Promise<void> {
    /* do something */
    /* You can use "await" here */
}

By looking at the code, I can point out the following differences:

  1. The async keywords: In typescript, this is merely a code marker. It does 2 things:
    • Force the return type to be Promise<void> instead of void. If you explicitly specify the return type to be non-promise (ex: void), typescript will spit an error at you.
    • Allow you to use await keywords inside the method.
  2. The return type is changed from void to Promise<void>
    • It means you can now do this:
      async someMethod(): Promise<void> { await componentDidMount(); }
  3. You can now use await keyword inside the method and temporarily pause its execution. Like this:

    async componentDidMount(): Promise<void> {
        const users = await axios.get<string>("http://localhost:9001/users");
        const questions = await axios.get<string>("http://localhost:9001/questions");
    
        // Sleep for 10 seconds
        await new Promise(resolve => { setTimeout(resolve, 10000); });
    
        // This line of code will be executed after 10+ seconds
        this.setState({users, questions});
        return Promise.resolve();
    }
    

Now, how could they cause troubles?

  1. The async keyword is absolutely harmless.
  2. I cannot imagine any situation in which you need to make a call to the componentDidMount() method so the return type Promise<void> is harmless too.

    Calling to a method having return type of Promise<void> without await keyword will make no difference from calling one having return type of void.

  3. Since there is no life-cycle methods after componentDidMount() delaying its execution seems pretty safe. But there is a gotcha.

    Let's say, the above this.setState({users, questions}); would be executed after 10 seconds. In the middle of the delaying time, another ...

    this.setState({users: newerUsers, questions: newerQuestions});

    ... were successfully executed and the DOM were updated. The result were visible to users. The clock continued ticking and 10 seconds elapsed. The delayed this.setState(...) would then execute and the DOM would be updated again, that time with old users and old questions. The result would also be visible to users.

=> It is pretty safe (I'm not sure about 100%) to use async with componentDidMount() method. I'm a big fan of it and so far I haven't encountered any issues which give me too much headache.