useEffect w/ Async Function

Async Function in useEffect

When you have async function like:

async () => { try { const response = await fetch(`https://www.reddit.com/r/${subreddit}.json`); const json = await response.json(); setPosts(json.data.children.map(it => it.data)); } catch (e) { console.error(e); } }

the try block would implcitly return a promise.

  • useEffect only expects a cleanup function as a return.

You have to be explicit about calling the async function:

useEffect(() => { async function fetchData() { try { const response = await fetch( `https://www.reddit.com/r/${subreddit}.json` ); const json = await response.json(); setPosts(json.data.children.map(it => it.data)); } catch (e) { console.error(e); } }; fetchData(); }, []);

You can also use IIFE:

useEffect(() => { (async function() { try { const response = await fetch( `https://www.reddit.com/r/${subreddit}.json` ); const json = await response.json(); setPosts(json.data.children.map(it => it.data)); } catch (e) { console.error(e); } })(); }, []);

Other Caveats

Do NOT extract the async function out.

  • It is NOT clear to the user whether the called async function has a cleanup function attached to it or not.
  • If the cleanup function is needed, it will lead to a memory leak.

Controlling the Render

Using setTimeOut, you can control the rendering behavior of the component.

  • this would come useful when a large amount of data needs to be fetched or screen needs to be coordinated while the context state is updating.
useEffect(() => { setIsLogingLoading(true); const fetchData = async () => { const data = fetch('url'); const result = await data.json(); setTimeout(() => { setIsLoginLoading(false); }, 1000); setSomeState(result); } fetchData(); }, []);

You can also chain two useEffect to use the result of one effect in the next:

useEffect(() => { setIsLoginLoading(true); const fetchData = async () => { const data = fetch('url'); const result = await data.json(); setTimeout(() => { setIsLoginLoading(false); }, 1000); // coordindated load/redirect time setSomeState(result); } fetchData(); }, []); useEffect(() => { if(isLoginLoading) { setTimeOut(() => { router.push('/') }, 1000) // coordindated load/redirect time } })