-
Notifications
You must be signed in to change notification settings - Fork 46.9k
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
Add Lazy Elements Behind a Flag #19033
Conversation
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit 21b624a:
|
Details of bundled changes.Comparing: 6071486...21b624a react-dom
react-art
react-reconciler
ReactDOM: size: 0.0%, gzip: -0.0% Size changes (experimental) |
We really needed this for Flight before as well but we got away with it because Blocks were lazy but with the removal of Blocks, we'll need this to ensure that we can lazily stream in part of the content. Luckily LazyComponent isn't really just a Component. It's just a generic type that can resolve into anything kind of like a Promise. So we can use that to resolve elements just like we can components. This allows keys and props to become lazy as well. To accomplish this, we suspend during reconciliation. This causes us to not be able to render siblings because we don't know if the keys will reconcile. For initial render we could probably special case this and just render a lazy component fiber. Throwing in reconciliation didn't work correctly with direct nested siblings of a Suspense boundary before but it does now so it depends on new reconciler.
Details of bundled changes.Comparing: 6071486...21b624a react-dom
react-art
ReactDOM: size: 0.0%, gzip: -0.0% Size changes (stable) |
Is that difference in behavior accidental or intentional? (Just curious.) |
Accidental. I mean we intentionally didn't put things that threw in reconciliation due to this quirk. So it wasn't observable before Blocks. The original source has to do with errors throwing. If an error throws inside an error boundary for whatever reason, we don't ever want to let that error boundary try to handle it. However, reconciling children isn't really part of the error boundary, it's just accidentally how it works. Even if we wanted to keep this for errors, it doesn't have to apply to suspense boundaries. It just accidentally did because we treated them same as errors. We could do the traversal one level up for throwing promises. However, since the new reconciler changes how suspense boundaries work, this issue accidentally got solved anyway. |
This now means that if a server component suspends, its value becomes a React.lazy object. I.e. the element that rendered the server component gets replaced with a lazy node. As of facebook#19033 lazy objects can be rendered in the node position. This allows us to suspend at the location of the server component while we're waiting on its content. Now server components has the same capabilities as Blocks to progressively reveal its content.
…0137) This now means that if a server component suspends, its value becomes a React.lazy object. I.e. the element that rendered the server component gets replaced with a lazy node. As of #19033 lazy objects can be rendered in the node position. This allows us to suspend at the location of the server component while we're waiting on its content. Now server components has the same capabilities as Blocks to progressively reveal its content.
…cebook#20137) This now means that if a server component suspends, its value becomes a React.lazy object. I.e. the element that rendered the server component gets replaced with a lazy node. As of facebook#19033 lazy objects can be rendered in the node position. This allows us to suspend at the location of the server component while we're waiting on its content. Now server components has the same capabilities as Blocks to progressively reveal its content.
We really needed this for Flight before as well but we got away with it because Blocks were lazy but with the removal of Blocks, we'll need this to ensure that we can lazily stream in part of the content.
Luckily LazyComponent isn't really just a Component. It's just a generic type that can resolve into anything kind of like a Promise.
So we can use that to resolve elements just like we can components. This allows keys and props to become lazy as well.
To accomplish this, we suspend during reconciliation. This causes us to not be able to render siblings because we don't know if the keys will reconcile. For initial render we could probably special case this and just render a lazy component fiber like we do with other lazy stuff. This is easier in blocking/concurrent mode only since the semantics for the LazyComponent tag is just to indefinitely suspend when rendered.
Throwing in reconciliation didn't work correctly with direct nested siblings of a Suspense boundary before but it does now so it depends on new reconciler.