44
votes

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
5
If a function returns a promise, you can await or .then(...), not both.Omagerio
This answers the question I guess, but in no way does this actually solves the problem. You are effectively starting a promise that might finish anytime. If your async job is not related to components's life cycle, then fine. But otherwise, you're going to run head first into troubles and hard to debug rendering bugs. I'm not experienced enough with React to be sure, but I feel like this messes with react's dependency system too.Romain Vincent

5 Answers

83
votes

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();
}, []);
12
votes

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);
  })();

}, []);
4
votes

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)
    }, [setData]);

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

Since getData returns a Promise you could just use .then

useEffect(() => {
    getData(1).then(setData);
}, []);
-2
votes

You can still define the async function outside of the hook and call it within the hook.

const fetchData = async () => {
   const data = await getData(1);
   setData(data);
}

useEffect(() => {
  fetchData();
}, []);