apearce/use-immediate-effect

Fundamentally broken

Opened this issue · 4 comments

In react strict-mode, hooks are sometimes executed a second time to check if the output is pure & the same (in some weird ass mode where console.log is overridden to hide log side effects).

This is however a fundamental issue with useImmediateEffect implementations, as the immediate effect is run again in this mode, and almost always has side effects.

Not sure this can be fixed. Leaving this here as a warning for others as it took me half a day to figure out what was going on.

This weird mode can be detected with import('react').__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner.current.mode === 9 btw, that could be a very hacky way to make this hook work as intended still.

This is not an issue with useImmediateEffect, it's just the way strict mode works. useEffect and useLayoutEffect behave the same way.

I'm curious what you are seeing and what your use case is.

Thanks for your response, but I'm afraid you're misunderstanding.

React in strict-mode sometimes does an extra render pass without running side-effects (so not doing things declared in useEffect or useLayoutEffect), and also not rendering children. But since the render() logic is called, effects with useImmediateEffect are executed. See also this comment for more info.

Our use case (otherwise irrelevant) is simply subscribing in some observable data pattern, then doing setState in the onChange callback. We would see that these subscriptions were leaking (and would get a lot of Can't perform a React state update on an unmounted component messages in development subsequently). It was extra confusing because console.logs weren't shown in this mode. Honestly whoever in the React team thought this was a good idea...

I had better success if I changed useEffect to useLayoutEffect on this line:

I guess the problem (for me) was that the component got unmounted so quickly so the effect never ran, so the cleanup function never got registered. With useLayoutEffect if works better.