I’ve been using useEffect
hooks heavily since React introduced them in version 16.8. A way to think of Effect hooks is like React lifecycle method (componentDidMount
, componentDidUpdate
, componentDWillUnmount
) bundled into one function, or hook as React defines it to perform side effects in function components.
Recently I came across the error Argument of type ‘() => Promise’ is not assignable to parameter of type ‘EffectCallback’. Type ‘Promise’ is not assignable to type ‘void | (() => void)
after attempting to run asynchronous code (async
and await
) inside the callback function of useEffect
hook.
There are two ways to solve prevent getting the error Argument of type ‘() => Promise’ is not assignable to parameter of type ‘EffectCallback’. Type ‘Promise’ is not assignable to type ‘void | (() => void)
:
- Define an
async
function inside theuseEffect
hook - Define an IIFE inside the
useEffect
hook
Solution #1 – Define an async function inside the useEffect hook
For this first solution, instead of using the async
and await
keywords to run asynchronous code inside the useEffect
, which is like the following piece of code,
import React, { useEffect } from 'react';
const MyComponent = () => {
useEffect(async () => {
const res = await fetch('https://randomuser.me/api/');
const data = await res.json();
const user = data.results?.[0];
console.log(user);
});
return <div>Hello World!</div>;
};
export default MyComponent;
you need to define an async
function inside the callback function and execute that function inside the useEffect
hook. Below is an example of what I’m referring:
import React, { useEffect } from 'react';
const MyComponent = () => {
useEffect(() => {
const fetchUser = async () => {
const res = await fetch('https://randomuser.me/api/');
const data = await res.json();
const user = data.results?.[0];
return user;
}
fetchUser();
});
return <div>Hello World!</div>;
};
export default MyComponent;
If you compare the previous two snippets of code, notice how the second snippet doesn’t define the useEffect
callback function as async
.
Instead, an anonymous function is defined inside the useEffect
callback function and assigned to the variable fetchUser
. That anonymous function uses the async
and await
keywords, enabling promised-based behavior. Finally, the fetchUser
function variable is executed. In that way, you can still run asynchronous logic inside useEffect
hooks.
Solution #2 – Define an IIFE inside the useEffect hook
The second solution is very similar to the previous solution. However, instead of defining an anonymous function inside the useEffect
callback function, you will need to execute an IIFE or Immediately Invoked Function Expression.
An IIFE (Immediately Invoked Function Expression) is a JavaScript function that runs as soon as it is defined.
MDN Web Docs
Take a look at how I use IIFE inside the useEffect
hook callback function to run promise-based asynchronous code.
import React, { useEffect } from 'react';
const MyComponent = () => {
useEffect(() => {
(async () => {
const res = await fetch('https://randomuser.me/api/');
const data = await res.json();
const user = data.results?.[0];
return user;
})();
});
return <div>Hello World!</div>;
};
export default MyComponent;