React how to cleanup setTimeout outside useEffect

Viewed 1479

If I use setTimeout and setState outside useEffect like this how do I clean it up on an unmount?

const MyComponents = () => {
  const [myState, setMyState] = useState(null);

  const handlePress = () => {
    setTimeout(() => {
      setMyState('...');
    }, 1000);
  };

  return <button onPress={handlePress} />;
};

If I leave the page (e.g the components unmounts) before the time is up i get

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.
1 Answers

Save the timeout id inside a reference and use it in cleanup effect:

const MyComponents = () => {
  const [myState, setMyState] = useState(null);

  const idRef = useRef();

  useEffect(() => {
    const timeoutId = idRef.current;
    return () => {
      clearTimeout(timeoutId);
    };
  }, []);

  const handlePress = () => {
    const id = setTimeout(() => {
      setMyState("...");
    }, 1000);
    idRef.current = id;
  };

  return <button onPress={handlePress} />;
};
Related