Skip to content

Bug - animations get stuck in exiting, "exited" never fires #817

@joshribakoff-sm

Description

@joshribakoff-sm

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.

Screen Shot 2022-04-13 at 11 55 48 AM

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions