FranklinOcean
FranklinOcean

Reputation: 106

I'm having trouble understanding how this useEffect is running with a fetch

I have a fetch inside of a useEffect hook. I'm console logging at different parts within it and getting some strange results

const [name, setName] = useState("Placeholder Name");
const [lat, setLat] = useState("Placeholder Lat");
const [long, setLong] = useState("Placeholder Long");
const [counter, setCounter] = useState(0);
const [loading, setLoading] = useState(true);

useEffect(() => {
  console.log("top level");
  fetch("https://api.wheretheiss.at/v1/satellites/25544")
    .then(res => res.json())
    .then(data => {
      console.log("inside fetch", name, long, lat);
      setName(data.name);
      setLat(data.latitude);
      setLong(data.longitude);
      setLoading(false);
    });
});

// Result on mount
top level 
inside fetch Placeholder Name Placeholder Long Placeholder Lat 
top level 
top level 
top level 
top level 
inside fetch iss Placeholder Long Placeholder Lat 
inside fetch iss 71.768808134445 27.26618722337
top level 
top level 
inside fetch iss 71.815373509259 27.312786482746

When the component mounts, I understand that the useEffect will run whenever a state value updates. There is a 1 second limit on that API endpoint so the effect will stop running when its current value matches the returned value.

My specific confusion is why "top level" is being logged 4 times in a row before the "fetch" console log is called. This may have to do with the asynchronous fetch, but I'm hoping someone could clarify.

Upvotes: 2

Views: 68

Answers (2)

Joseph D.
Joseph D.

Reputation: 12174

Since react hooks doesn't batch state updates by default, here's a step by step explanation of the behaviour:

top level // initial render
inside fetch Placeholder Name Placeholder Long Placeholder Lat // prior to re-render
top level // re-render: from setName()
top level // re-render: from setLat()
top level // re-render: from setLong()
top level // re-render: from setLoading()
inside fetch iss Placeholder Long Placeholder Lat // name updated

// The lines below could run infinitely every time long, lat changes
inside fetch iss 71.768808134445 27.26618722337 // long, lat updated
top level // re-render: new value for lat - setLat()
top level // re-render: new value for long - setLong()
inside fetch iss 71.815373509259 27.312786482746 // long, lat updated

Upvotes: 1

Travis James
Travis James

Reputation: 1939

Every time you set state with one of the useState callbacks the component re renders.

You are setting a state value 4 times in a row so the component re renders 4 time in a row very quickly. Every time it renders it is calling your useEffect hook because you don’t have an array of dependencies. So it’s console.logging 4 times in a row because the rest of the function is async

Upvotes: 1

Related Questions