-
Notifications
You must be signed in to change notification settings - Fork 46.5k
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
[Fiber] Fix portal bugs #8532
[Fiber] Fix portal bugs #8532
Changes from 6 commits
8eb192b
3ba8069
4596fc4
cb8184f
3f2129a
ed9747d
c69be1c
4fe06f5
8b65c56
9db4d21
eb5636d
a0ce225
9ccd1ad
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 |
---|---|---|
|
@@ -152,7 +152,7 @@ module.exports = function<T, P, I, TI, C, CX>( | |
// If we don't have a child, try the siblings instead. | ||
continue siblings; | ||
} | ||
if (!node.child) { | ||
if (!node.child || node.tag === HostPortal) { | ||
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. This was non-obvious to me. Could use a comment. 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. done |
||
continue siblings; | ||
} else { | ||
node.child.return = node; | ||
|
@@ -265,16 +265,19 @@ module.exports = function<T, P, I, TI, C, CX>( | |
// After all the children have unmounted, it is now safe to remove the | ||
// node from the tree. | ||
removeChild(parent, node.stateNode); | ||
// Don't visit children because we already visited them. | ||
} else if (node.tag === HostPortal) { | ||
// When we go into a portal, it becomes the parent to remove from. | ||
// We will reassign it back when we pop the portal on the way up. | ||
parent = node.stateNode.containerInfo; | ||
// Visit children because portals might contain host components. | ||
if (node.child) { | ||
node = node.child; | ||
continue; | ||
} | ||
} else { | ||
commitUnmount(node); | ||
// Visit children because we may find more host components below. | ||
if (node.child) { | ||
// TODO: Coroutines need to visit the stateNode. | ||
node.child.return = node; | ||
|
@@ -302,10 +305,22 @@ module.exports = function<T, P, I, TI, C, CX>( | |
} | ||
|
||
function commitDeletion(current : Fiber) : void { | ||
// Recursively delete all host nodes from the parent. | ||
const parent = getHostParent(current); | ||
// Detach refs and call componentWillUnmount() on the whole subtree. | ||
unmountHostComponents(parent, current); | ||
// Recursively delete the closest child host nodes from the closest host parent. | ||
// Then detach refs and call componentWillUnmount() on the whole subtree. | ||
if (current.tag === HostPortal) { | ||
// When deleting a portal, there are no host nodes above it. | ||
// It is a host parent itself. | ||
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. 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. Because of the recursive case which gets us into 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 could probably inline it there if we know for sure that portal can never be tagged with a deletion effect (can it not? I don’t understand that part well) 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. The "can render nested portals" test definitely gets a Alternatively we could figure out how to avoid tagging portals themselves with 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. It can. But my question is why calling 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. My theory is that we shouldn't need this extra tag check because we're going to need one inside 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. If the portal gets the unmount, then we should hit this https://github.com/gaearon/react/blob/c69be1c5f499e24dd08878df612321edc6a8135f/src/renderers/shared/fiber/ReactFiberCommitWork.js#L274 before we reach the 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. Hmm you're right, I don't understand this. 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. Apparently something is being deleted twice in some loop. 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. Hm. Well that seems to be the problem then. |
||
const parent = current.stateNode.containerInfo; | ||
let child = current.child; | ||
while (child) { | ||
unmountHostComponents(parent, child); | ||
child = child.sibling; | ||
} | ||
} else { | ||
// When deleting anything other than a portal, search for the host parent. | ||
const parent = getHostParent(current); | ||
unmountHostComponents(parent, current); | ||
} | ||
|
||
// Cut off the return pointers to disconnect it from the tree. Ideally, we | ||
// should clear the child pointer of the parent alternate to let this | ||
|
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.
An alternate solution could be
portal.children || []
.This is also a problem with HostRoot so we should choose a consistent strategy.
https://github.com/facebook/react/blob/master/src/renderers/shared/fiber/ReactFiberReconciler.js#L163
However, I'm also considering using an effect tag to indicate the lack or existence of pendingProps instead.