reactjs / react-transition-group

An easy way to perform animations when a React component enters or leaves the DOM
https://reactcommunity.org/react-transition-group/
Other
10.13k stars 651 forks source link

CSSTransition--jerky behavior if "in" attribute is toggled mid-transition (related: #463) #543

Open leonyjiang opened 5 years ago

leonyjiang commented 5 years ago

What is the current behavior?

If the 'in' attribute is toggled while an enter or exit transition is occurring, the component will "snap" to its initial exit or enter style (specified under 'item-exit' or 'item-enter' if classNames attribute is 'item'), respectively, and begin its CSS transition in the reverse direction. This behavior is jerky and undesirable.

What is the expected behavior?

The component transitions smoothly, with the CSS transition in the reverse direction beginning where the current transition left off at. The expected behavior is demonstrated in the right column of the CodeSandbox below. This may be an uncommon use case that CSSTransition was not designed for, so please suggest any possible workarounds.

Could you provide a CodeSandbox demo reproducing the bug?

https://codesandbox.io/s/csstransition-issue-bocvg To recreate the behavior, refer to the sections above or the SandboxInfo.

richardscarrott commented 3 years ago

Hi @silvenon -- not sure if you've seen the above issue, but I'm experiencing this same problem and we're working around it by adding the CSS transition declaration to the .enter / .exit classes in addition to the .enter-active and .exit-active classes which works, e.g. https://codesandbox.io/s/csstransition-issue-forked-4v6jk

However, this explicitly goes against the documentation which says:

-active classes represent which styles you want to animate to, so it's important to add transition declaration only to them, otherwise transitions might not behave as intended! This might not be obvious when the transitions are symmetrical, i.e. when -enter-active is the same as *-exit, like in the example above (minus transition), but it becomes apparent in more complex transitions.

Our transitions are symmetrical which is probably why it seems fine -- but I wondered if there was a better way to solve this?

silvenon commented 3 years ago

🤔 It's possible that in effort to explain *-active classes I have been too specific in the documentation, considering that this library can be used for so many purposes. In this particular case it sounds like adding transition rules to .content-enter and .content-exit is the right way to go, if that's the case I should ease up on the documentation there, but I'd like to know a bit more about your use case. While the demo is very nice, react-transition-group solves problems which CSS transitions alone cannot solve, so demos should not be too simple. 😄

leonyjiang commented 3 years ago

Hi y'all, it's been a while since I opened this issue, and I'm really racking my brain to remember the exact use case. The problem may have had to do with adding and deleting a component that transitioned in and out using CSSTransition. If you deleted it before it finished transitioning in, it looked jerky. This library was used over pure CSS because the desired behavior was for the opacity transition to occur while the component mounted (which I couldn't figure out using CSS). Again, I'm not 100% sure, but it was something along those lines. Hope this helps give some insight into the problem!

silvenon commented 3 years ago

Thanks! It's ok that you don't remember, my request was directed mostly at @richardscarrott, I assumed you solved the problem considering the fact that you closed the issue. I'll think about the add/delete scenario, too, and generally about interrupting transitions. 🤔

richardscarrott commented 3 years ago

@silvenon yeah our use case is the same; an enter animation when a component mounts.

To be more specific we have a <Drawer /> component that slides into view, which can potentially render large sub-trees so we don't want to render it until it's actually opened. This is a simplified example -- https://codesandbox.io/s/csstransition-issue-forked-2x8m6?file=/index.js

silvenon commented 3 years ago

Yeah, when I wrote that part of documentation I was thinking of transitions which are fast, potentially asymmetric and when the starting position isn’t the same as the default. At some point it comes down to whether it works the way you want, I was being too prescriptive. The most important thing about react-transition-group is understanding how it works, then you can tailor styles to exactly what you want, which we ultimately can’t know and shouldn’t try too hard to predict when writing the docs.

Btw, if this demo indeed accurately depicts your situation, then you don’t need TransitionGroup, and instead of .drawer-open you can use .drawer-enter-done, and .drawer-enter styles are unnecessary because they are the same as .drawer. Here’s the updated example how I would write it: https://codesandbox.io/s/csstransition-issue-forked-kxn5n?file=/index.js, my personal preference is to write .drawer styles in the open state instead of closed, and using mountOnEnter and unmountOnExit, but maybe you had a reason for not using those features.

richardscarrott commented 3 years ago

Yes I did originally use mountOnEnter and unmountOnExit however for SEO we needed it to always be rendered in some situations (e.g. when we render the navigation in the drawer) and we wanted the initial state of open / closed to work.

re: the use of TransitionGroup, we actually use it because we sometimes combine react-transition-group with react-gateway which works by mounting / unmounting it's children in a separate sub-tree TransitionGroup's management of children worked nicely e.g.

https://codesandbox.io/s/csstransition-issue-forked-2u22h?file=/index.js