Home > Blockchain >  clearTimeout prevents setTimeout from running
clearTimeout prevents setTimeout from running

Time:10-25

  const func = () => {
    const id = setTimeout(() => {
      //do something with an element
    }, 300);
    return id;
  };

  useEffect(() => {
    const id = func();
    return () => clearTimeout(id);
  }, [click]);

When I click too fast, which is the trigger to the useEffect, it could cause the function passed to setTimeout to not be runned.

What is the problem?

Is the following alternative solution just as good?

  const func = () => {
    const id = setTimeout(() => {
      if (element is stilled defined) {
      // do something  
      }
    }, 300);
    return id;
  };

  useEffect(() => {
    func();
  }, [click]);

CodePudding user response:

If I understand your code correctly it seems you are wanting to delay a callback function by some delta. I suggest using a React ref to track an array of running timers. When the function is invoked, add the new timeout id to this array, when the timeout expires clear it from the array. Use an onUnmount useEffect to cleanup any running timeouts.

const timeoutRef = useRef([]);

const func = () => {
  const id = setTimeout(() => {
    //do something with an element
    dequeueCallback(id);
  }, 3000);
  enqueueCallback(id);
};

const enqueueCallback = (id) => {
  timeoutRef.current.push(id);
};
const dequeueCallback = (id) => {
  timeoutRef.current = timeoutRef.current.filter((el) => el !== id);
};

useEffect(() => {
  // clear any running timeouts upon unmount
  return () => {
    timeoutRef.current.forEach(clearTimeout);
  };
}, []);

Demo

Edit cleartimeout-prevents-settimeout-from-running

CodePudding user response:

You can resolve this issue by cleanup function, the cleanup function will trigger when the effect rerender is trigger, so you can put what is must happen before any action, so that, the solution will just by this:

  useEffect(() => {
    console.log(myEvent);
    // You can add condtion here and above of cleaner
    const timer = setTimeout(() => {
      if(myEvent !== null){// Internal contion
        alert("HI MAN");
      }
    }, 2000);

    return () => clearTimeout(timer);// This is important part
  }, [myEvent]);

check this example:

import { useEffect, useState } from "react";
import "./styles.css";

export default function App() {
  const [myEvent, setMyEvent] = useState(null);

  useEffect(() => {
    console.log(myEvent);
    
    const timer = setTimeout(() => {
      if(myEvent !== null){
        alert("HI MAN");
      }
    }, 2000);

    return () => clearTimeout(timer);
  }, [myEvent]);

  return (
    <div className="App">
      <button onClick={() => {
        setMyEvent(Math.random);
      }}>test</button>
    </div>
  );
}

And this is URL Demo.

React Referance: React Hooks

  • Related