Search code examples
reactjsasynchronousasync-awaitaxiospage-lifecycle

React. Api request inside of a useEffect hook (Calling an async function)


I'm building a project in React and I got a component that holds several components. This component needs to fetch data when mounted and later when changes occur on the child components. At first, I tried using the useEffect hook with a "shouldRefetch" dependency like so:

[shouldRefetch, setShouldRefetch] = useState(false);

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

const fetchData = async () => {
    // fetchingdata.. 
    setData(response.data); //useState hook
    setShouldRefetch(false);
}

const onFetch = () = {
    setShouldRefetch(true);
}

//child component

return (
 <Child onFetch={onFetch} />
)

After this code sent too many requests to my API, I tried passing the child component the fetchData function and removed the dependency from the useEffect:

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

// ...

return (
 <Child fetchData={fetchData} />
)

This solved most duplicate api calls but when the page loads I'm still getting two api calls being sent out in the network tab (chrome dev tools). I know it's becuase of the useEffect but I don't undertand why. Can anyone help me undertand this issue?

Thanks in advance

I tried fetching data on page load and expecting it to occur only once and later only when I call my async function to fetch data. I just don't understand why I'm seeing a request being fired twice in the network tab.


Solution

  • You may have enabled 'React.StrictMode'. In this case every useEffect() on your component will run twice on mount by default. You may find this configuration on your index.tsx file (for typescript). You can fix this by removing the StrictMode wrapper but that won't be the best solution. Because you can do a trick to prevent api call from running twice,

      let isFetching = false;
    
      const fetchData = () => {
        fetch("/dummy.json").then((res) => {
          console.log(res);
        });
      };
    
      useEffect(() => {
        if (isFetching) return;
        fetchData();
        isFetching = true;
      }, []);
    

    Here, we have declared a variable outside of useEffect() with default value false. After executing the fetch function we have set isFetching = true. As we are checking isFetching in the first line of useEffect() this will prevent the fetchData() function to run 2nd time and your fetch api call will only run once on component mount.