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?
Your code is fine and very readable to me. See this Dale Jefferson's article where he shows an async
componentDidMount
example and looks really good as well.But some people would say that a person reading the code may assume that React does something with the returned promise.
So the interpretation of this code and if it is a good practice or not is very personal.
If you want another solution, you could use promises. For example:
I think it's fine as long as you know what you're doing. But it can be confusing because
async componentDidMount()
can still be running aftercomponentWillUnmount
has run and the component has unmounted.You may also want to start both synchronous and asynchronous tasks inside
componentDidMount
. IfcomponentDidMount
was async, you would have to put all the synchronous code before the firstawait
. It might not be obvious to someone that the code before the firstawait
runs synchronously. In this case, I would probably keepcomponentDidMount
synchronous but have it call sync and async methods.Whether you choose
async componentDidMount()
vs synccomponentDidMount()
callingasync
methods, you have to make sure you clean up any listeners or async methods that may still be running when the component unmounts.When you use
componentDidMount
withoutasync
keyword, the doc say this:If you use
async componentDidMount
you will loose this ability: another render will happen AFTER the browser update the screen. But imo, if you are thinking about using async, such as fetching data, you can not avoid the browser will update the screen twice. In another world, it is not possible to PAUSE componentDidMount before browser update the screenUpdate:
(My build: React 16, Webpack 4, Babel 7):
When using Babel 7 you'll discover:
Using this pattern...
you will run into the following error...
Uncaught ReferenceError: regeneratorRuntime is not defined
In this case you will need to install babel-plugin-transform-runtime
https://babeljs.io/docs/en/babel-plugin-transform-runtime.html
If for some reason you do not wish to install the above package (babel-plugin-transform-runtime) then you will want to stick to the Promise pattern...
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:By looking at the code, I can point out the following differences:
async
keywords: In typescript, this is merely a code marker. It does 2 things:Promise<void>
instead ofvoid
. If you explicitly specify the return type to be non-promise (ex: void), typescript will spit an error at you.await
keywords inside the method.void
toPromise<void>
async someMethod(): Promise<void> { await componendDidMount(); }
You can now use
await
keyword inside the method and temporarily pause its execution. Like this:Now, how could they cause troubles?
async
keyword is absolutely harmless.I cannot imagine any situation in which you need to make a call to the
componentDidMount()
method so the return typePromise<void>
is harmless too.Calling to a method having return type of
Promise<void>
withoutawait
keyword will make no difference from calling one having return type ofvoid
.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 now execute and the DOM would be updated again, this 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
withcomponendDidMount()
method. I'm a big fan of it and so far I haven't encountered any issues which give me too much headache.