-
Notifications
You must be signed in to change notification settings - Fork 47.2k
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
Refactor Partial Hydration #16346
Refactor Partial Hydration #16346
Conversation
ReactDOM: size: 0.0%, gzip: 0.0% Details of bundled changes.Comparing: c203471...3243916 react-dom
react-art
react-test-renderer
react-reconciler
react-native-renderer
Generated by 🚫 dangerJS |
scripts/error-codes/codes.json
Outdated
@@ -338,5 +338,7 @@ | |||
"337": "An invalid event responder was provided to host component", | |||
"338": "ReactDOMServer does not yet support the fundamental API.", | |||
"339": "An invalid value was used as an event responder. Expect one or many event responders created via React.unstable_createResponer().", | |||
"340": "An invalid value was used as an event listener. Expect one or many event listeners created via React.unstable_useResponer()." | |||
"340": "An invalid value was used as an event listener. Expect one or many event listeners created via React.unstable_useResponer().", |
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.
@trueadm Noticed a typo here. Should be unstable_useResponder()
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.
I’m on PTO. cc @necolas
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.
Oh yeah, sorry. I mean I can do it too :D
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.
if (current === null || current.memoizedState !== null) { | ||
if ( | ||
current === null || | ||
(current.memoizedState: null | SuspenseState) !== null |
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.
Why is this necessary? ^
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.
It's so that it becomes greppable.
Once we add types for fields like memoizedState it will also be used to ensure that those types are correct, as we make that change.
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.
The type SuspenseState should probably be nullable by itself since it has meaning and would be a variant if we had those.
We now store the comment node on SuspenseState instead and that indicates that this SuspenseComponent is still dehydrated. We also store a child but that is only used to represent the DOM node for deletions and getNextHostSibling.
Forked based on SuspenseState.dehydrated instead.
We can now simplify the logic for retrying dehydrated boundaries without hydrating. This is becomes simply a reconciliation against the dehydrated fragment which gets deleted, and the new children gets inserted.
Instead we use the regular Suspense path. To save code, we attach retry listeners in the commit phase even though technically we don't have to.
I think this is right...?
The DidCapture flag isn't used consistently in the same way. We need further refactor for this.
If we remove the dehydration status in the first pass and then do a second pass because we suspended, then we need to continue as if it didn't previously suspend. Since there is no fragment child etc. However, we must readd the deletion.
b708aaa
to
a108e3f
Compare
This now doesn't represent a suspense boundary itself. Its parent does. This Fiber represents the fragment around the dehydrated content.
It does a two pass render that client renders the content.
Avoids the temporary mutable variables. I kept losing track of them.
Placing it in the type since that's the central point as opposed to spread out.
a108e3f
to
3243916
Compare
This is a pretty invasive refactor of the SuspenseComponent and DehydratedSuspenseComponent.
The primary purpose of this refactor is to avoid the hacky "upgrade" and "downgrade" by mutating the tag.
In the new model, a boundary is always represented by the same SuspenseComponent fiber. Inside it I store a "DehydratedFragment". The inner fiber represents the dehydrated nodes in the tree. This can be used to delete the whole thing or insert before it.
I also switched legacy mode to always client-render the boundary content since we can't hydrate partially in legacy mode. It also warns.
Otherwise, this (hopefully) shouldn't have an semantic differences.