Home > Enterprise >  useEffect fetch request is pulling data twice
useEffect fetch request is pulling data twice

Time:05-16

What I Want:

I'm pulling data from an api, then setting the data to state. I've done this inside a useEffect hook, but when I console.log the data afterwards, it's displaying the data twice, sometimes 4 times. I'm at a loss as to why this is happening.

What I've Tried:

  • console.log within useEffect to see data from source
  • disabling react developer tools within chrome.

My Code:

// make api call, assign response to data state
const [apiData, setApiData] = useState();

useEffect(() => {
    async function fetchData() {
      try {
        await fetch('https://restcountries.com/v3.1/all')
        .then(response => response.json())
        .then(data => setApiData(data));
      } catch (e) {
        console.error('Error fetching api data', e);
      };
    };
    fetchData();
}, []);

console.log(apiData);

Result of console.log:

error screenshot

CodePudding user response:

If you are using React version 18 , StrictMode has a behavior change. Before it wasn't running effects twice, now it does to check for bugs. ( Actually, it does mount-remount, which causes initial render effects to fire twice)

https://reactjs.org/blog/2022/03/29/react-v18.html#new-strict-mode-behaviors

CodePudding user response:

As was mentioned in the other comment this is due to effects being "double invoked" in strict-mode.

A common solution and one I believe has been suggested by the React team (although am struggling to find where I read this) is to use useRef.

// make api call, assign response to data state
const [apiData, setApiData] = useState();
const hasFetchedData = useRef(false);

useEffect(() => {
    async function fetchData() {
      try {
        await fetch('https://restcountries.com/v3.1/all')
        .then(response => response.json())
        .then(data => setApiData(data));
      } catch (e) {
        console.error('Error fetching api data', e);
      };
    };
    if (hasFetchedData.current === false) {
      fetchData();
      hasFetchedData.current = true;
    } 
}, []);
  • Related