How to replace a simple SetTimeout and ClearTimeout with requestAnimationFrame in React?

368 Views Asked by At

Here is my code block using setTimeout and clearTimeout which I want to replace with requestAnimationFrame -

const MyComponent = () => {
  const [copyText, setCopyText] = useState("Copy");
  const copyTextHandler = () => {
    setCopyText("Copied");
    const timer = setTimeout(() => {
      setCopyText("copy");
    }, 3000);
    return () => {
      clearTimeout(timer);
    };
  };
  
  return (<button onClick={copyTextHandler} disabled={copyTextHandler === "Copied"}>{copyText}</button>)
}

I tried searching for a few solutions in stack overflow and other platforms but couldn't find a fix for it.

1

There are 1 best solutions below

3
motto On BEST ANSWER

The short answer is "you shouldn't, because setTimeout is the way to do this".

However, if you absolutely have to use requestAnimationFrame then you can use it to repeatedly check if it's time to change the text.

You could do this by passing a time at which the text should change back:

  const changeTextChecker = (time) => {
    if (Date.now() > time) {
      setCopyText("copy");
    } else {
      requestAnimationFrame(() => changeTextChecker(time));
    }
  };

Sandbox

But I prefer to set a timeout to set a flag that indicates that the time has passed, because this is more in keeping with the thinking behind this task:

  useEffect(() => {
    const changeTextChecker = () => {
      if (shouldChangeText.current) {
        setCopyText("copy");
        shouldChangeText.current = false; // reset for next time
      } else requestAnimationFrame(changeTextChecker);
    };
    requestAnimationFrame(changeTextChecker);
  }, []);

Sandbox

In both cases you are circumventing Javascript's asynchronous event queue by polling rather than just using the appropriate tool for the task. However, it does exactly answer your question.