2

I'm a beginner with React and I am trying to call this API every 3 seconds to get the International Space Station coordinates and render them to the screen every call. So I fetch the API coordinates using setTimeout(), update the 'coords' state variable, and then use useEffect to update the ref 'coordRef' to those values, which I then pass to the child component, 'TomTomSearch', to use as well.

The problem is that when I run it in strict mode it makes many API calls and then eventually a never-ending stream of API calls, as seen by the multiple console logs during runtime, where as when I run it without the strict mode tags, it only calls it once per setTimeout() call. The API I'm using has a limit of 1 call/second and it always ends up giving me a 429 error eventually in strict mode.

145 FetchISS.js:21 fetched //(console logged 145 times in 15 seconds)
FetchISS.js:17 
GET https://api.wheretheiss.at/v1/satellites/25544 
429 (Too Many Requests)

I just need to know if this is just a side effect of using strict mode, or if I'm actually just doing this the wrong way. Also, any pointers or recommendations on any ugly code you see would be greatly appreciated!

function FetchISS() {
  const [ coords, setCoords] = useState({lat: null, lon: null});
  const coordRef = useRef({lat: null, lon: null});

  useEffect(
    () => {
      coordRef.current = {lat: coords.lat, lon: coords.lon};
    }
  ,[coords]);

  function fetchISS() {
    const iss_API = 'https://api.wheretheiss.at/v1/satellites/25544';
    fetch(iss_API)
    .then(results => results.json())
    .then(results => {
      setCoords({lat: results.latitude, lon: results.longitude});
      console.log('fetched');
    }).catch(err => {
      console.log(err.message);
    })
  }

  setTimeout(() => fetchISS(), 3000);

  return(
    <div>
      { coordRef.current.lat !== null && coordRef.current.lon !== null ? 
      <TomTomSearch coords={coords} /> : null } 
    </div>
  )
}
skyboyer
  • 22,209
  • 7
  • 57
  • 64

1 Answers1

0

You are creating an infinite loop of fetching in your component. When the API responds, your component re-renders, and since your setTimeout call is not inside of a useEffect call it is run every time the component is rendered, creating a cycle.

Refer to this question for how to call a function every few seconds in react.

Scoder12
  • 50
  • 1
  • 8
  • You're saying the fetch call itself causes a re-render? Or the fact that I set my state within the fetch call causes a re-render? I have tried placing my setTimeout() function in the useEffect call but I get the same results, an infinite loop.. If I put the setTimeout in a useEffect call, will the component wait for that to be done before re-rendering? – Dillon Kyle May 26 '21 at 18:04
  • I think I figured it out: I put my API call logic into a fetchISS() function. Then I call useEffect() twice in my component. The first call is with an empty dependency array so it is only called once. The second useEffect call has a dependency of a state object called 'effectCall', which I specifically created for calling it. In both useEffect calls I change the value of 'effectCall' so that it re-renders the component. I use this to change the state of 'effectCall': – Dillon Kyle May 26 '21 at 19:06
  • const [ effectCall, setEffectCall ] = useState(false); setEffectCall(prev => !prev); – Dillon Kyle May 26 '21 at 19:11
  • Forgot to mention: in the second useEffect, (the one with the dependency), I have that one call fetchISS() on a 3 second setInterval(). I hope this helps anyone else having this problem, and I hope it is an adequate solution. – Dillon Kyle May 26 '21 at 19:14