Hacker News new | ask | show | jobs
by afidrya 2142 days ago
It contains a very serious breaking change: cleanup in useEffect is now being executed asynchronously. I might not be seeing something, but I think this means all patterns like the one below will now have hard to catch racing conditions.

  const [x, setX] = useState()
  useEffect(() => {
    let isMounted = true
    someAsyncFunc(result => {
      if (isMounted) {
        setX(result) // should not be called on dismounted component
      }
    })
    return () => { isMounted = false }
  }, [])
  return <MyComponent x={x} />
In this example it's possible that component will be unmounted, then completion handler will run and try to modify state before cleanup function will be able to set the flag.

Imo choosing a different name for new useEffect would be better (like useAsyncEffect or introducing a parameter), because just changing its behavior won't even result in compilation errors or guaranteed run-time errors, only make old code unstable.

Is there a way to reliably detect if component is still mounted before updating it when doing async operations in effects?

1 comments

Thanks for raising this concern. This particular example is not a problem in practice because React will not fire the warning about setting state in the short period between unmounting and cleanup. (We have special code and tests specifically for this case.)

So code like this can stay written exactly as it does today. As noted in the blog post we’ve only had to modify ~20 components out of thousands so although this change may cause some breakage (please report anything unusual to the issue tracker!) we’re fairly confident that such common patterns continue to work.

(Edit: added this to the post.)