user967451
user967451

Reputation:

Updated state value is not reflected inside setInterval() in React

I have the following:

const [isPaused, setIsPaused] = useState(false);
const myTimer = useRef(null);

const startTimer = () => {
  myTimer.current = setInterval(() => {
    console.log(isPaused); // always says "false"
  }, 1000);
};

Elsewhere in the code while this timer is running I'm updating the value of isPaused:

setIsPaused(true);

But this isn't reflected in the console log, it always logs false. Is there a fix to this?

Upvotes: 4

Views: 2869

Answers (2)

ezio4df
ezio4df

Reputation: 4125

You can do something like this,

  const [isPaused, setIsPaused] = useState(false);
  const myTimer = useRef(null);

  const startTimer = () => {
    myTimer.current = setInterval(() => {
      console.log(isPaused); // now updates
    }, 1000);
  };

  useEffect(() => {
    startTimer();
    return () => myTimer.current != null && clearInterval(myTimer.current);
  }, [isPaused]);

  return (
    <div>
      <b>isPaused: {isPaused ? "T" : "F"}</b>
      <button onClick={() => setIsPaused(!isPaused)}>Toggle</button>
    </div>
  );

Use Others function

use useInterval from 30secondsofcode

const Timer = props => {
  const [seconds, setSeconds] = React.useState(0);
  useInterval(() => {
    setSeconds(seconds + 1);
  }, 1000);

  return <p>{seconds}</p>;
};

ReactDOM.render(<Timer />, document.getElementById('root'));

Or, use react-useInterval package

function Counter() {
  let [count, setCount] = useState(0);
 
  const increaseCount = amount => {
    setCount(count + amount);
  };
 
  useInterval(increaseCount, 1000, 5);
  return <h1>{count}</h1>;
}

Upvotes: 0

Joseph D.
Joseph D.

Reputation: 12174

The myTimer.current never changed which means isPaused is always false inside the function.

You need to make use of useEffect to update myTimer.current every time isPaused is updated.

useEffect(() => {
  function startTimer() {
    myTimer.current = setInterval(() => {
      console.log(isPaused);
    }, 1000);
  };
  
  startTimer();
  return () => clearInterval(myTimer.current); // cleanup
}, [isPaused]);

Upvotes: 6

Related Questions