[SOLVED] Why a simple `useEffect` is not taking updated value when it is warping any "setInterval/timeout" inside

Issue

Why a simple useEffect is not taking updated value when it is warping any setInterval/timeout inside;

Code sandbox

where variable stopped to initial value;

import { useState, useEffect } from "react";
let timerRef;
const StopWatch = () => {
  const [time, setTime] = useState(0);
  const [isPause, setPause] = useState(false);
  useEffect(() => {
    timerRef = setInterval(() => {
      console.log({ time });
      if (!isPause) {
        setTime(time + 1);
      }
    }, 5000);
    return () => clearInterval(timerRef);
  }, []);
  const startWatch = () => {
    setPause(false);
  };
  const stopWatch = () => {
    setPause(true);
  };
  return (
    <>
      time: {time}
      <button onClick={startWatch}>Start</button>
      <button onClick={stopWatch}>stop</button>
    </>
  );
};
export { StopWatch };

output

Solution

That is because you are accessing time value from the closure, and since you are defining setTimeout handler only once (on initialization) then it will always refer to that initial value for time. I suggest, for this use case, just to use state updater with callback, and like that it will provide you mechanism to easily update state with previos one, and by not accessing state directly. Just rewrite setTime(_time + 1) to setTime(prevTime => prevTime + 1)

Answered By – Milos Pavlovic

Answer Checked By – Clifford M. (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published.