How to use async function in React hooks useEffect (Typescript/JS)?

Andréas Hanss
Oct 18, 2019 · 2 min read

👾At first glance, you could have the idea to do something similar to get your content from a remote API as an example.

const MyFunctionnalComponent: React.FC = (props) => {
useEffect(async () => {
await loadContent();
}, []);
return <div></div>;
}

🤔 What’s wrong with that?

If you’re using Typescript, the compiler should be yielding something like this :

Argument of type '() => Promise<void>' is not assignable to parameter of type 'EffectCallback'.

Let’s see why this error appears by taking the definition of what an async function is:

A function that allows to use asynchronous instructions with the await keyword which will block the statement execution as long as the Promise after which the await keyword is doesn’t resolve…

All right seems great… but wait…

This function will also return a Promise, no matter if you explicitly return something or not. In case you return data, it will be wrapped in the resolving content of the promise that the function will create and return automatically.

Huh! Did you start seeing the problem here? No? Let’s read about the useEffect hook here to get more information: https://reactjs.org/docs/hooks-reference.html#useeffect

Often, effects create resources that need to be cleaned up before the component leaves the screen, such as a subscription or timer ID. To do this, the function passed to useEffect may return a clean-up function. For example, to create a subscription.

📌 Using an async function makes the callback function return a Promise instead of a cleanup function.

And that’s why the compiler is yielding in Typescript. This pattern is also not working in plain JS as React is not waiting for a promise.

💡How to deal with asynchronous code in useEffect ?

By using the following technique, we will be able to use async function in our effects :

const MyFunctionnalComponent: React.FC = props => {
useEffect(() => {
// Create an scoped async function in the hook
async function anyNameFunction() {
await loadContent();
}
// Execute the created function directly
anyNameFunction();
}, []);
return <div></div>;
};

Now, your code is safe as you are returning nothing at all and the compiler has stopped yielding.

🎬 Bonus / TLDR; 📦

You can also use an IIFE, which has the same effect as above.

If you don’t know what an IIFE is: it is described here by my Friend Sunil Sandhu.

const MyFunctionnalComponent: React.FC = props => {
useEffect(() => {
// Using an IIFE
(async function anyNameFunction() {
await loadContent();
})();
}, []);
return <div></div>;
};

Andréas Hanss

Written by

👨🏻‍💻Javascript Tech leads @ Kaliop 🇫🇷 — react | react-native | modern js |🔥 Firebase — https://modern-javascript.fr. Passionnated about learning.

JavaScript in Plain English

Learn the web's most important programming language.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade