0

I'm trying to use a state number to maintain the time of each interval but when I update the state value the interval remains the same. Here's my codesandbox:

import React, { useEffect, useState } from "react";

export default function App() {
  const [slideIndex, setSlideIndex] = useState<number>(1);
  const [intervalTime, setIntervalTime] = useState<number>(3000); // every 3 seconds

  useEffect(() => {
    const interval = setInterval(() => {
      setSlideIndex((slideIndex) => slideIndex + 1);
      console.log("but interval time is still: " + intervalTime);
    }, intervalTime); //  remains 3 seconds after clicking button
    return () => clearInterval(interval);
  }, []);

  const handleButtonClick = () => {
    setIntervalTime(1000);
    console.log("Interval time should be: " + intervalTime);
  };

  return (
    <div className="App">
      <h2>Counter: {slideIndex}</h2>
      <button onClick={() => handleButtonClick()}>
        shorten interval to 1 second
      </button>
    </div>
  );
}
Samuel Zrna
  • 149
  • 1
  • 1
  • 9
  • 3
    You need to add `intervalTime` to the dependency array of the useEffect. `useEffect(() => { ... }, [intervalTime]);` – pilchard Feb 22 '23 at 23:42
  • @Konrad this isn't a closure issue, just a dependency issue – pilchard Feb 22 '23 at 23:50
  • @pilchard this question is a textbook example of a stale closure – Konrad Feb 22 '23 at 23:53
  • If you are only looking at the logged value, yes there is a stale closure. But the issue is that the useEffect needs to be run again in order to reset the interval, using a ref as your duplicate suggests will log correctly, but not reset the interval. And the `setSlideIndex` is correctly avoiding closure issues by using a callback. – pilchard Feb 22 '23 at 23:53
  • And the solution proposed by the duplicate is poor at best as it suggests duplicating the state value into a ref for the sole purpose of logging it, rather than maintaining a single source of truth ie by using `useCallback` – pilchard Feb 23 '23 at 00:03

0 Answers0