Darkbound
Darkbound

Reputation: 3444

setState with setInterval in it gets triggered 3 times

I have a chart that I made with chartJS that I update in a way that makes an animation, and I do that with setInterval, I wanted to be able to pause/resume the animation.

So I created a state variable that tracks the interval ID so that I can kill it when the pause button is clicked:

const intervalIDs = [];

function App() {
  const [times, setTimes] = useState(2); // variable that I need to change to make my animation work
  const [allData, setAllData] = useState([]);
  const [paused, setPaused] = useState(false);
  const [animationIntervalID, setAnimationIntervalID] = useState();
  
  useEffect(() => {
      setAllData(calculateNewData()); // recalculate data for the chart when times changes
  }, [times])


  const startVisualizationHandler = () => {
    console.log("called"); // gets called once as it should
    setAnimationIntervalID(prevInterval => {
      console.log("setting interval"); // this gets called just ONCE
    
      let intervalID = setInterval(() => {
          setTimes(prevTimes => prevTimes + 0.1);
      }, 100);

      intervalIDs.push(intervalID); // this pushes THREE interval ID's into the intervals array

      return intervalID;
    });
  }

  const pauseVisualizationHandler = () => {
    clearInterval(animationIntervalID);
    setAnimationIntervalID(prevID => undefined);
  }

  const resumeVisualizationHandler = () => {
    startVisualizationHandler();
  }

  const handlePause = () => {
    setPaused(pauseStatus => {
      !pauseStatus ? pauseVisualizationHandler() : resumeVisualizationhandler();
 
      return !pauseStatus;
    });
  }

  return (
    <>
      <div style={{ maxHeight: 600, maxWidth: 600, height: 600, width: 600, display: "inline-block" }}>
        <Line data={allData} options={options} width={null} height={null} />
        <button id={"vishandler"} onClick={startVisualizationHandler}>
          VISUALIZE
        </button>
        <button id={"pausehandler"} onClick={handlePause}>
          {paused ? `RESUME` : `PAUSE`}
        </button>
      </div>
    </>
  );
}

When I run the code, with multiple console.logs spread out throughout the code, I have tracked everything, and when I click the pause/resume button, everything gets called just once in order, just like it should. However, the setAnimationIntervalID within startVisualizationHandler is acting extremely wierd, the console.log("setting interval"); gets called just once, but intervalIDs.push(intervalID); gets called 3 times, because when I log intervalIDs I see 3 IDs.

What I am trying to do is:

-> onClick on the VISUALIZE button -> start the animation - this is working, BUT it also ends up firing multiple setIntervals (which to me basically means that the pause/resume functionality is irrelevant to the issue)

-> onClick on the PAUSE button -> pause the animation - this is also working

-> onClick on the RESUME button -> resume the animation - this is also working BUT it ends up firing multiple setIntervals.

Upvotes: 0

Views: 77

Answers (1)

buzatto
buzatto

Reputation: 10382

this is related to React.StrictMode wrapping your App Application. StrictMode doesn't affect production, only development to find potencial problems. it does that by rerending your component, which results in these unexpected behavior.

to fix it, remove the wrapping StrictMode tag from your App.

Upvotes: 1

Related Questions