Search code examples
reactjsuse-effect

useEffect hook using outdated variables in child functions


I am trying to use the useEffect hook as a way to create an async timer in react. The logic is inside of timeFunc(), and the useEffect is working such that it calls the function every 1000ms. The weird part is, for some reason when timeFunc() gets called (every one sec) it's only accesses the old variable values, (specifically "paused"). For example, if the interval starts with a value of "paused" being false, even if I change 'paused' to be true (paused is a state variable passed in by the parent component), timeFunc() will still think paused is false. Can't figure it out. Any help appreciated!

Code:

  //TIMER MANAGER
  let timeFunc = () => {
    if(paused == false){
      let delta = Math.trunc((new Date() - resumedTime)/1000);
      setProgress(delta);
      console.log('test + ' + paused);
    } else {
      clearInterval(interval);
    }
  }
  useEffect(() => {
      let interval = null;
        interval = setInterval(() => {
          timeFunc();
        }, 1000);
      return () => clearInterval(interval);
    }, [initialized]);

Solution

  • The timeFunc depends on having an up-to-date value of paused, but it doesn't exist in the useEffect's dependency array.

    Either add it to the dependency array and also store the time until the next interval in state, or use a ref for paused instead (with a stable reference) (or in addition to state), eg:

    const pausedRef = useRef(false);
    // ...
    const timeFunc = () => {
      if (!pausedRef.current) {
        // ...
    
    // to change it:
    pausedRef.current = !pausedRef.current;
    

    Also note that

    let interval = null;
      interval = setInterval(() => {
        timeFunc();
      }, 1000);
    

    simplifies to

    const interval = setInterval(timeFunc, 1000);