'Avoid infinite loop with useEffect dependencies

I am stuck in an infinite loop while trying to enforce the exhaustive dependency rule.

Take this for example - adjust the address bar when we change to a different step in a form.

// routes is an array like
// ['step1', 'step2']

// When we change the step (click a button) let's update the address bar
useEffect(() => {
  const route = routes[step];
  if(route){
    const path = `/${route}`;
    if(path !== location.pathname){
       history.push(path)
    }
  }
}, [history, location.pathname, routes, step]);

// When we change the address bar (press back, refresh) let's update the step
useEffect(() => {
  if(params.step){
     const step = routes.indexOf(params.step);
     if(step > -1){
        setStep(step);
     }   
  }
}, [params, routes]);

So what happens here - we load the page fine. We navigate with buttons fine. But then we hit back.

  1. params changes - so we call setStep in the second useEffect. Address bar is up to date
  2. But before step change triggers the first useEffect, location.pathname triggers it. It then uses the stale state of step which was the previous step, calling history.push and setting it back to the last step.

Continue to infinity.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source