What is the current behavior?
Around 0.1% of the time [in React 18, not sure if related] onExited doesn't fire
What is the expected behavior?
onExit should always fire
Could you provide a CodeSandbox demo reproducing the bug?
Unfortunately I have only been able to reproduce this in a larger app using Material UI.
We have intermittent bugs where the MUI Menu randomly leaves a Backdrop covering our whole page with 0% opacity.
Through debugging what I originally thought was an MUI issue in the React devtools, I can see MUI fails to hit this condition https://github.com/mui/material-ui/blob/master/packages/mui-base/src/PopperUnstyled/PopperUnstyled.js#L202-L204
The only possible explanation (that I can think of) is that react-transition-group fails to inform the consuming MUI component that the animation is done. The result is that my backdrop has 0% opacity, but MUI never unmounts it, so it steals clicks from the whole page and appears our app is "frozen".
I noticed here is where you set the EXITING, https://github.com/reactjs/react-transition-group/blob/master/src/Transition.js#L272-L280 I'm not sure I follow this callback logic, but here you conditionally bail out of the callback https://github.com/reactjs/react-transition-group/blob/master/src/Transition.js#L302-L307 it must be related, I am speculating.
Here is where I think it's canceling the callback https://github.com/reactjs/react-transition-group/blob/master/src/Transition.js#L190-L192 and the reason that line runs is that when I select a menu item I update state in my app that triggers something unrelated to suspend in a transition, and I think React 18 reconciler may be doing something funky where it unmounts and remounts stuff with the original state preserved https://reactjs.org/blog/2022/03/29/react-v18.html#new-strict-mode-behaviors
React simulates mounting the component with the previous state.
I think it may do something similar if the tree above suspends?
If it happens to unmount in between EXITING and EXITED, it cancels the callback. Later on when React 18 restores the tree, it restores it to the EXITING state but there is no longer any callback pending to move it towards the terminal state of EXITED, therefore I'm left with this artifact in my UI of a div with 0% opacity preventing clicks.

Around 0.1% of the time [in React 18, not sure if related]
onExiteddoesn't fireonExitshould always fireUnfortunately I have only been able to reproduce this in a larger app using Material UI.
We have intermittent bugs where the MUI
Menurandomly leaves aBackdropcovering our whole page with 0% opacity.Through debugging what I originally thought was an MUI issue in the React devtools, I can see MUI fails to hit this condition https://github.com/mui/material-ui/blob/master/packages/mui-base/src/PopperUnstyled/PopperUnstyled.js#L202-L204
The only possible explanation (that I can think of) is that
react-transition-groupfails to inform the consuming MUI component that the animation is done. The result is that my backdrop has 0% opacity, but MUI never unmounts it, so it steals clicks from the whole page and appears our app is "frozen".I noticed here is where you set the
EXITING, https://github.com/reactjs/react-transition-group/blob/master/src/Transition.js#L272-L280 I'm not sure I follow this callback logic, but here you conditionally bail out of the callback https://github.com/reactjs/react-transition-group/blob/master/src/Transition.js#L302-L307 it must be related, I am speculating.Here is where I think it's canceling the callback https://github.com/reactjs/react-transition-group/blob/master/src/Transition.js#L190-L192 and the reason that line runs is that when I select a menu item I update state in my app that triggers something unrelated to suspend in a transition, and I think React 18 reconciler may be doing something funky where it unmounts and remounts stuff with the original state preserved https://reactjs.org/blog/2022/03/29/react-v18.html#new-strict-mode-behaviors
I think it may do something similar if the tree above suspends?
If it happens to unmount in between EXITING and EXITED, it cancels the callback. Later on when React 18 restores the tree, it restores it to the EXITING state but there is no longer any callback pending to move it towards the terminal state of EXITED, therefore I'm left with this artifact in my UI of a div with 0% opacity preventing clicks.