JadenB
JadenB

Reputation: 67

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!

Upvotes: 1

Views: 624

Answers (2)

Farista Latuconsina
Farista Latuconsina

Reputation: 353

How about to use a local variable that keeps track of whether the component is mounted or not.

useEffect(() => {
  let run = true;

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

  if (run) {
    timeOut.timeout1();
    timeOut.timeout2();
  }

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

Upvotes: 0

Shubham Khatri
Shubham Khatri

Reputation: 281894

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]);

Upvotes: 1

Related Questions