Mateusz W
Mateusz W

Reputation: 66

Why my React component is still updating state even if I do cleanup in useEffect()?

I've got a little problem there and I dont know why my solution is not working properly. Here is the code:

    const [progress, setProgress] = useState(0);

    useEffect(() => {
        let isMounted = true; 
        if(isMounted === true) {
            progress < 100 && setTimeout(() => setProgress(progress + 1), 20); 
        }
        return () => isMounted = false;
      }, [progress]);

Im doing there setTimeout async operation. Every 20ms i want to set state of progress by 1. Thats all. Also I added isMounted variable which contains state of component.

The problem is that when lets say, I mount this component and I unmount this immediately after 1s maybe two then i dont get this error. If I wait longer and unmount the component (before setTimeout has time to change the progress state to 100, which is the limit) then this error appears.

Why this error is appearing in such weird way?

Why does this error even appear when the component has clearly communicated when it is mounted and when not?

Upvotes: 1

Views: 56

Answers (1)

Nick
Nick

Reputation: 16576

You need to either clear the timeout in the cleanup or use your isMounted variable within the timeout itself.

Clearing the timeout:

useEffect(() => {
  let timeout; 
  if (progress < 100) {
    timeout = setTimeout(() => {
      setProgress(progress + 1)
    }, 20); 
  }
  return () => { clearTimeout(timeout) };
}, [progress]);

Using the isMounted variable:

useEffect(() => {
  let isMounted = true; 
  if (progress < 100) {
    setTimeout(() => {
      if (isMounted) setProgress(progress + 1); 
    }, 20)
  }
  return () => { isMounted = false };
}, [progress]);

Upvotes: 2

Related Questions