Search code examples
reactjssettimeoutuse-effect

Why does the setTimeOut not being cleared by using clean up function in React (useEffect)?


I want to have all of the setTimeOut cleared when the component is unmounted. Even though I have use clearTimeOut as a clean up function but the error still persis: "Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function"

useEffect(() => {
     const timeOut = {timeout1: ()=>setTimeout(() => setProgress((preV) => preV + 15), [
        550,
      ]),timeout2 : ()=> setTimeout(() => setMessage("All most done"), [500])}
      timeOut.timeout1();
      timeOut.timeout2();


    return () => {
      clearTimeout(timeOut.timeout1);
      clearTimeout(timeOut.timeout2);
    };
  }, [progress,message]);

Does anyone know how to solve this issue? Any help would be appreciated!


Solution

  • timeout1 isn't storing the returned value of setTimeout which is the timerId but its storing the reference of the function that executes timeout

    You could write your code in a way that it executes the timeouts immediately using Immediately invoked functions so that timeout1 and timeout2 have timerIds

    useEffect(() => {
         const timeOut = {
               timeout1: (()=>setTimeout(() => setProgress((preV) => preV + 15), 550))(),
               timeout2 : (()=> setTimeout(() => setMessage("All most done"), 500))()
         }
    
    
    
        return () => {
          clearTimeout(timeOut.timeout1);
          clearTimeout(timeOut.timeout2);
        };
      }, [progress,message]);
    

    however you could simply run the timeouts without writing them as IIFE

    useEffect(() => {
         const timeOut = {
               timeout1: setTimeout(() => setProgress((preV) => preV + 15), 550),
               timeout2 : ()=> setTimeout(() => setMessage("All most done"), 500)
         }
    
    
    
        return () => {
          clearTimeout(timeOut.timeout1);
          clearTimeout(timeOut.timeout2);
        };
      }, [progress,message]);