2

In one of my components I have a useEffect setup where an interval is set to fetch a function.

It's basically set up as follows:

...

const token = useToken() // custom hook that updates whenever access_token updates

const fetchData = useCallback(() => {
  callAPI(token)
}, [token])

useEffect(() => {
  if (!token) return

  fetchData()

  const interval = setInterval(fetchData, 60000)

  return () => {
    clearInterval(interval)
  }
}, [token]}

...

It is supposed fetchData every 60 seconds which it does.

What it also needs to do (which it doesn't) is whenever the token is updated, it should account for that.

What I've currently done to try solve that is clear the interval when the token changes and start the process over. But I think I've handled that incorrectly in my attempts above.

Any idea on how to accomplish this correctly?

Vicky
  • 134
  • 9
Barry Michael Doyle
  • 9,333
  • 30
  • 83
  • 143
  • when token changes do you also what to call `fetchData` or just make sure that it uses the updated token? – Ramesh Reddy May 05 '21 at 14:27
  • Just want to make sure it uses the updated token, I'm not too phased if it does recall `fetchData` though. But first prize would be to stick to 60 second intervals and just if the token updates, use the new one :) – Barry Michael Doyle May 05 '21 at 14:29

1 Answers1

1

the only thing missing is fetchData should be added to the dependency array to make sure that the useEffect uses the updated callback

useEffect(() => {
    if (!token) return

    fetchData()

    const interval = setInterval(fetchData, 60000)

    return () => {
        clearInterval(interval)
    }
}, [token, fetchData])

but you can also move the fetchData(this time fetchData doesn't have to be memorized with useCallback) function inside the useEffect, that way you can only have token as a dependency:

useEffect(() => {
    const fetchData = () => {
        if(!token) return;

        callAPI(token)
    };

    fetchData();
    const interval = setInterval(fetchData, 60000)

    return () => {
        clearInterval(interval)
    }
}, [token])

Edit: You can remove token form the useEffect this way:

const fetchData = useCallback(() => {
    if(!token) return; // moved the token check here
    
    callAPI(token)
  }, [token])
  
useEffect(() => {
    fetchData();
    const interval = setInterval(fetchData, 60000)

    return () => {
        clearInterval(interval)
    }
}, [fetchData])
Ramesh Reddy
  • 10,159
  • 3
  • 17
  • 32
  • I'll give that a shot and let you know if that solves it :) – Barry Michael Doyle May 05 '21 at 14:40
  • I don't understand why `fetchData` needs to be added to the dependency array of that `useEffect` though. – Barry Michael Doyle May 05 '21 at 15:23
  • It's confusing because `fetchData` is also using token as a dependency. When token changes fetchData gets updated and useEffect will also trigger but the function that is known to the useEffect may not be the latest fetchData. – Ramesh Reddy May 05 '21 at 15:26
  • Ok interesting, yeah I've been a bit confused by this because I thought `useEffect` dependency array values work a little differently to useCallback since they're what trigger a re-rerun. Wouldn't this theoretically mean I don't need to keep `token` in the `useEffect` dependency array anymore then since it's already covered in `fetchData`? – Barry Michael Doyle May 05 '21 at 15:29
  • @BarryMichaelDoyle Yes, you can do that. But you have to make sure that the token is not used anywhere else in the `useEffect` other than inside `fetchData`. Updated my answer. – Ramesh Reddy May 05 '21 at 15:33
  • 1
    Ok, fantastic that makes sense :) Thanks, just busy testing everything and making sure it works! – Barry Michael Doyle May 05 '21 at 15:44