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.1k stars 652 forks source link

Bug: In react 18, flashing effect appears at the end of exit phase before entering #816

Open tranvansang opened 2 years ago

tranvansang commented 2 years ago

What is the current behavior?

When clicking the button image

What is the expected behavior?

Phase 3 shouldn't exist in react 18 renderer.

Could you provide a CodeSandbox demo reproducing the bug?

In demo's index.js, try changing legacyReact value to switch react 18 behav

https://user-images.githubusercontent.com/13043196/162848290-d2c339e7-ec75-45e3-84e0-298a6ea092e1.mp4

ior.

https://codesandbox.io/s/wonderful-glade-n0n92s?file=%2Fsrc%2Findex.js

sotarules commented 2 years ago

Friends, I have what I believe is the same issue, but in my case I'm animating a slide transition from right-to-left using 3D translate affecting the X value.

The "new" component enters from the right, while the "old" component simultaneously exits to the left.

What I'm seeing a perfectly executed transition until the very end, and then you see a brief flash of the old exiting component superimposed over the newly-entered component.

In theory, it should be impossible to see the old exited component at the end of the animation because the 3D translate rules, if processed as designed, would mean the exited component X value would place the old component 100% off screen. There should be no way to "see" the brief flash of the old exited component.

I am confident that the cause of this problem is the React 18 update batching, because I've been able to ameliorate the problem by doing the safeSetState using flushSync.

IMPORTANT: It is apparently only necessary to "wrap" the nextState value of exited with flushSync; all other nextState values (entering, entered, exiting) can be done using setState in the normal manner.

I believe that state-transitions exiting and exited are being erroneously combined into a single batch update by React 18.

This cannot be permitted, or the animation will be impacted.

The updates for exiting and exited must not be batched.

It is necessary to fully process the exiting state before setting exited state.

I hope this makes sense, this stuff is very complicated and hard to get your head around. Here is my fix.

 safeSetState(nextState, callback) {
      // This shouldn't be necessary, but there are weird race conditions with
      // setState callbacks and unmounting in testing, so always make sure that
      // we can cancel any pending setState callbacks after we unmount.
      callback = this.setNextCallback(callback)
      this.setStateConditionalFlushSync(nextState, callback)
  }

  /**
   * Prevent React 18 from batching updates.
   *
   * @param {object} nextState Next state object.
   * @param {function} callback Post-set callback.
   */
  setStateConditionalFlushSync(nextState, callback) {
      console.log(`Transition.js setStateConditionalFlushSync nextState=${JSON.stringify(nextState)}`)
      if (nextState?.status !== "exited") {
          console.log(`Transition.js setStateConditionalFlushSync *imperative* nextState=${JSON.stringify(nextState)}`)
          this.setState(nextState, callback)
          return
      }
      flushSync(() => {
          console.log(`Transition.js setStateConditionalFlushSync *flushSync* nextState=${JSON.stringify(nextState)}`)
          this.setState(nextState, callback)
      })
  }
tranvansang commented 1 year ago

@sotarules

thanks!! so much, buddy.

I have patched the package using your fix, and now it WORKs LIKE A CHARM!!

jcampuza commented 1 year ago

It doesn't seem to me this was ever fixed/released even though this is marked as completed?

tranvansang commented 1 year ago

not fixed yet with the recently released version 4.4.5

here is the commit to fix https://github.com/reactjs/react-transition-group/commit/c20af7cd51ce9217a7ebd7ebd9b70e242960d7b9

asapach commented 1 year ago

not fixed yet with the recently released version 4.4.5

are there any plans to fix this and release a new version?

ermolaev-unlimint commented 1 year ago

This bug is still relevant.

ermolaev-unlimint commented 1 year ago

This bug is still relevant.

sergei-startsev commented 1 year ago

@tranvansang is there a chance to release a new version with the fix?

tranvansang commented 1 year ago

@tranvansang is there a chance to release a new version with the fix?

here it is

react-transition-group-react-18

or you can patch locally (tutorial)

sergei-startsev commented 1 year ago

@tranvansang I expected the existing package to be fixed rather than a new package being released.

tranvansang commented 1 year ago

Im not the author of the package. Cannot publish any new version of it

sergei-startsev commented 1 year ago

I'm guessing there was confusion caused by the commit attached above. What prevented you from creating PR?

asapach commented 1 year ago

@tranvansang I've found an alternate fix to your original issue: you can set animation-fill-mode: forwards to your styles. Here is the sandbox: https://codesandbox.io/s/bug-react-transition-group-with-react-18-forked-2m8993?file=/src/styles.css

asapach commented 1 year ago

I've created a PR: #885