Open tranvansang opened 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)
})
}
@sotarules
thanks!! so much, buddy.
I have patched the package using your fix, and now it WORKs LIKE A CHARM!!
It doesn't seem to me this was ever fixed/released even though this is marked as completed?
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
not fixed yet with the recently released version 4.4.5
are there any plans to fix this and release a new version?
This bug is still relevant.
This bug is still relevant.
@tranvansang is there a chance to release a new version with the fix?
@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)
@tranvansang I expected the existing package to be fixed rather than a new package being released.
Im not the author of the package. Cannot publish any new version of it
I'm guessing there was confusion caused by the commit attached above. What prevented you from creating PR?
@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
I've created a PR: #885
What is the current behavior?
When clicking the button
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 behavhttps://user-images.githubusercontent.com/13043196/162848290-d2c339e7-ec75-45e3-84e0-298a6ea092e1.mp4
ior.
https://codesandbox.io/s/wonderful-glade-n0n92s?file=%2Fsrc%2Findex.js