Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call an async function inside a UseEffect() in React?

I would like to call an async function and get the result for my UseEffect.

The fetch api examples i found on the internet are directly made in the useEffect function. If my URL changes, i must patch all my fetchs.

When i tried, i got an error message.

This is my code.


    async function getData(userId) {
        const data = await axios.get(`http://url/api/data/${userId}`)
            .then(promise => {
                return promise.data;
            })
            .catch(e => {
                console.error(e);
            })
            return data;
    }


    function blabla() {
        const [data, setData] = useState(null);

        useEffect(async () => {
            setData(getData(1))
        }, []);

        return (
            <div>
                this is the {data["name"]}
            </div>
        );
    }

index.js:1375 Warning: An effect function must not return anything besides a function, which is used for clean-up. It looks like you wrote useEffect(async () => ...) or returned a Promise. Instead, write the async function inside your effect and call it immediately:

useEffect(() => {
  async function fetchData() {
    // You can await here
    const response = await MyAPI.getData(someId);
    // ...
  }
  fetchData();
}, [someId]); // Or [] if effect doesn't need props or state
like image 659
Yassine Layachi Avatar asked Jul 01 '19 15:07

Yassine Layachi


People also ask

Can I call async function in useEffect?

Either way, we're now safe to use async functions inside useEffect hooks. Now if/when you want to return a cleanup function, it will get called and we also keep useEffect nice and clean and free from race conditions. Enjoy using async functions with React's useEffect from here on out!

How do I use async in useEffect?

Anti-Pattern: async function directly in the useEffect React can run this async function but can not run the cleanup function. Don't use raw async function directly in the useEffect. useEffect(async () => { console. log('Hi :)') return () => { console.info('Bye!

Why does the callback function in the useEffect hook Cannot be asynchronous?

You cannot directly make the callback function supplied to the useEffect hook async because: async functions implicitly return a promise, and; useEffect expects its callback to either return nothing or a clean-up function.

How do you call a function once in useEffect?

Here is an example of how you would call a function to fetch data only once - when the component mounts. Copied! import {useEffect, useState} from 'react'; const App = () => { const [data, setData] = useState({data: []}); const [err, setErr] = useState(''); useEffect(() => { // 👇️ this only runs once console.


4 Answers

Create an async function inside your effect that wait the getData(1) result then call setData():

useEffect(() => {   const fetchData = async () => {      const data = await getData(1);      setData(data);   }    fetchData(); }, []); 
like image 70
Fraction Avatar answered Oct 02 '22 10:10

Fraction


If you're invoking it right-away you might want to use it as an anonymous function:

useEffect(() => {    (async () => {      const data = await getData(1);      setData(data);   })();  }, []); 
like image 21
hsusanoo Avatar answered Oct 02 '22 10:10

hsusanoo


It would be best if you did what the warning suggests - call the async function inside the effect.

    function blabla() {
        const [data, setData] = useState(null);

        useEffect(() => {
            axios.get(`http://url/api/data/1`)
             .then(result => {
                setData(result.data);
             })
             .catch(console.error)
        }, []);

        return (
            <div>
                this is the {data["name"]}
            </div>
        );
    }

If you want to keep the api function outside of the component, you can also do this:

    async function getData(userId) {
        const data = await axios.get(`http://url/api/data/${userId}`)
            .then(promise => {
                return promise.data;
            })
            .catch(e => {
                console.error(e);
            })
            return data;
    }


    function blabla() {
        const [data, setData] = useState(null);

        useEffect(() => {
            (async () => {
                const newData = await getData(1);
                setData(newData);
            })();
        }, []);

        return (
            <div>
                this is the {data["name"]}
            </div>
        );
    }
like image 31
zilijonas Avatar answered Oct 02 '22 09:10

zilijonas


Since getData returns a Promise you could just use .then

useEffect(() => {
    getData(1).then(setData);
}, []);
like image 24
YingYang Avatar answered Oct 02 '22 09:10

YingYang