Do I need to clearTimeout in react function?

Viewed 2091

I am using 'setTimout()' in a function and I am not calling that function in 'useEffect()' do I still need to find a way to clear timeout?

const RandomComponent = () =>{

  const [clicked, setClicked] = useState(false);

  const aFunction = () => {
    setTimeout(()=>{
      setClicked(true);
    },1000);
  }

  return (
    <div>
      <button onClick={aFunction}>Click me!</button>
    </div>  
  )

}

Something like above code, in this situation do I need to clear timeout? thanks

*Updated question:

const RandomComponent = () =>{

  const [clicked, setClicked] = useState(false);

  const aFunction = (evt) => {
    return setTimeout(()=>{
      setClicked(true);
    },30000);
  }

  useEffect(()=>{
    return ()=>{
      // how to clear setTimeout in 'aFunction' when I unmount this component?
    }
  });

  return (
    <div>
      <button onClick={aFunction}>Click me!</button>
    </div>  
  )

}

1 Answers

You only need to clear the timeout if you want the timer not to fire if it hasn't already fired. If it's already fired, or you don't care if it fires in the future, you don't need to cancel it.

Since you're starting the timer on a button click, if the timer callback uses state information when it runs (the one in the question doesn't), the state information it closes over may be stale, but it can get fresh state information via the setter function if it needs it. But if the timer might fire after the component is unmounted, using the setter like that would cause an error about updating state on an unmounted component. It's hard to give you a general solution to that, as a general solution is usually not as good as a solution that's specific to what you're doing in the timer callback.


In a comment you've asked:

if when the time comes and I need to clean up/clear my setTimeout in a function when I unmount the component, how do I do it? cause if I am calling setTimeout in useEffect I can just put the setTimeout in a variable and clearTimeout(theSetTimoutVariable) inside of return function in useeffect but how do I do it in a function that is going to get called by onClick button with an event argument?

The fact is I don't know the "right" React way to do that, and I'd like to.

I know of a way to do it, which is to use useEffect with an empty dependency array and non-state instance data, like this:

// A utility function that cancels a timer callback if necessary and
// returns a 0 you can assign to the timer handler variable
function cancelTimer(handle) {
    if (handle) {
        clearTimer(handle);
    }
    return 0;
}

const Example = () => {
    // Non-state instance data
    const {current: instance} = useRef({});

    // Cleanup on dismount
    useEffect(() => {
        // Mounting
        // ...

        return () => {
            // Dismounting

            // If we have an outstanding timer, cancel it
            instance.timer = cancelTimer(instance.timer);
        };
    }, []); // <=== Empty array means the callback is only called on mount,
            //      and the one it returns is only called on dismount

    const onButtonClick = () => {
        instance.timer = cancelTimer(instance.timer);
        instance.timer setTimeout(() => {
            // ...
        }, 1000);
    };

    return (/*...*/);
};
Related