-
Notifications
You must be signed in to change notification settings - Fork 51.1k
Fix Ref Lifecycles in Hidden Subtrees #31379
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
bdfe9fe
a2c9e7a
2101de0
1426f6d
52c0e97
a0685eb
4036c91
1b7c7ee
dc0c3a5
82bea69
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1325,7 +1325,9 @@ function commitDeletionEffectsOnFiber( | |
| } | ||
| case ScopeComponent: { | ||
| if (enableScopeAPI) { | ||
| safelyDetachRef(deletedFiber, nearestMountedAncestor); | ||
| if (!offscreenSubtreeWasHidden) { | ||
| safelyDetachRef(deletedFiber, nearestMountedAncestor); | ||
| } | ||
| } | ||
| recursivelyTraverseDeletionEffects( | ||
| finishedRoot, | ||
|
|
@@ -1335,7 +1337,9 @@ function commitDeletionEffectsOnFiber( | |
| return; | ||
| } | ||
| case OffscreenComponent: { | ||
| safelyDetachRef(deletedFiber, nearestMountedAncestor); | ||
| if (!offscreenSubtreeWasHidden) { | ||
| safelyDetachRef(deletedFiber, nearestMountedAncestor); | ||
| } | ||
| if (disableLegacyMode || deletedFiber.mode & ConcurrentMode) { | ||
| // If this offscreen component is hidden, we already unmounted it. Before | ||
| // deleting the children, track that it's already unmounted so that we | ||
|
|
@@ -1572,7 +1576,7 @@ function recursivelyTraverseMutationEffects( | |
| lanes: Lanes, | ||
| ) { | ||
| // Deletions effects can be scheduled on any fiber type. They need to happen | ||
| // before the children effects hae fired. | ||
| // before the children effects have fired. | ||
| const deletions = parentFiber.deletions; | ||
| if (deletions !== null) { | ||
| for (let i = 0; i < deletions.length; i++) { | ||
|
|
@@ -1637,7 +1641,7 @@ function commitMutationEffectsOnFiber( | |
| commitReconciliationEffects(finishedWork); | ||
|
|
||
| if (flags & Ref) { | ||
| if (current !== null) { | ||
| if (!offscreenSubtreeWasHidden && current !== null) { | ||
| safelyDetachRef(current, current.return); | ||
| } | ||
| } | ||
|
|
@@ -1660,7 +1664,7 @@ function commitMutationEffectsOnFiber( | |
| commitReconciliationEffects(finishedWork); | ||
|
|
||
| if (flags & Ref) { | ||
| if (current !== null) { | ||
| if (!offscreenSubtreeWasHidden && current !== null) { | ||
| safelyDetachRef(current, current.return); | ||
| } | ||
| } | ||
|
|
@@ -1745,7 +1749,7 @@ function commitMutationEffectsOnFiber( | |
| commitReconciliationEffects(finishedWork); | ||
|
|
||
| if (flags & Ref) { | ||
| if (current !== null) { | ||
| if (!offscreenSubtreeWasHidden && current !== null) { | ||
| safelyDetachRef(current, current.return); | ||
| } | ||
| } | ||
|
|
@@ -1961,7 +1965,7 @@ function commitMutationEffectsOnFiber( | |
| } | ||
| case OffscreenComponent: { | ||
| if (flags & Ref) { | ||
| if (current !== null) { | ||
| if (!offscreenSubtreeWasHidden && current !== null) { | ||
| safelyDetachRef(current, current.return); | ||
| } | ||
| } | ||
|
|
@@ -2074,10 +2078,12 @@ function commitMutationEffectsOnFiber( | |
| // TODO: This is a temporary solution that allowed us to transition away | ||
| // from React Flare on www. | ||
| if (flags & Ref) { | ||
| if (current !== null) { | ||
| if (!offscreenSubtreeWasHidden && current !== null) { | ||
| safelyDetachRef(finishedWork, finishedWork.return); | ||
| } | ||
| safelyAttachRef(finishedWork, finishedWork.return); | ||
| if (!offscreenSubtreeIsHidden) { | ||
| safelyAttachRef(finishedWork, finishedWork.return); | ||
| } | ||
|
Comment on lines
+2081
to
+2086
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @kassens, I think this is the correct behavior. You were right that
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you sure about this behavior? We don't check for Offscreen anywhere else that we attach.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
We actually do, but it's implicit. Every other type calls In both of these, we prune traversal when we encounter a hidden
I'm not sure why I don't plan to change this as part of fixing refs, though. I considered an alternative in which I leave
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I traced the origin of that comment (which was harder than I expected due to the reconciler forking and unforking that happened) and found this: #19264
I don't fully understand the context, but I figured that it would be helpful to know its origin.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ~~After writing unit tests for this bug, I've confirmed that these changes are actually not needed to prevent I've dropped these changes for now.~~ Oh… just kidding, I was not running
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I confirmed that |
||
| } | ||
| if (flags & Update) { | ||
| const scopeInstance = finishedWork.stateNode; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the unit test for "ignores ref for Activity in hidden subtree", I discovered that this and the call from
commitMutationEffectsOnFiberare triggered, causingXto be incorrectly invoked twice! 🤯