Skip to content
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

Merged
merged 1 commit into from
May 28, 2020
Merged

Conversation

sebmarkbage
Copy link
Collaborator

@sebmarkbage sebmarkbage commented May 28, 2020

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.

@facebook-github-bot facebook-github-bot added React Core Team Opened by a member of the React Core Team CLA Signed labels May 28, 2020
@codesandbox-ci
Copy link

codesandbox-ci bot commented May 28, 2020

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:

Sandbox Source
fast-butterfly-mopql Configuration

@sizebot
Copy link

sizebot commented May 28, 2020

Details of bundled changes.

Comparing: 6071486...21b624a

react-dom

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-dom-test-utils.development.js 0.0% -0.0% 75.66 KB 75.66 KB 20.24 KB 20.23 KB UMD_DEV
react-dom-unstable-fizz.browser.development.js 0.0% -0.1% 5.36 KB 5.36 KB 1.81 KB 1.8 KB UMD_DEV
react-dom-test-utils.production.min.js 0.0% -0.0% 13.18 KB 13.18 KB 4.9 KB 4.9 KB UMD_PROD
ReactDOMTesting-dev.js 0.0% -0.0% 937.86 KB 937.86 KB 209.53 KB 209.53 KB FB_WWW_DEV
react-dom-unstable-fizz.browser.production.min.js 0.0% -0.3% 1.2 KB 1.2 KB 706 B 704 B UMD_PROD
react-dom.development.js +0.1% +0.1% 953.13 KB 954.44 KB 208.44 KB 208.56 KB UMD_DEV
react-dom-server.browser.development.js 0.0% -0.0% 144.77 KB 144.77 KB 36.93 KB 36.93 KB UMD_DEV
react-dom.production.min.js 🔺+0.1% 🔺+0.2% 125.44 KB 125.63 KB 40.18 KB 40.25 KB UMD_PROD
ReactDOMForked-dev.js +0.1% +0.1% 1.02 MB 1.02 MB 233.31 KB 233.46 KB FB_WWW_DEV
react-dom-server.browser.production.min.js 0.0% -0.0% 20.34 KB 20.34 KB 7.52 KB 7.52 KB UMD_PROD
react-dom.profiling.min.js +0.1% +0.1% 129.55 KB 129.74 KB 41.41 KB 41.47 KB UMD_PROFILING
ReactDOMForked-prod.js 🔺+0.2% 🔺+0.1% 431.13 KB 432.04 KB 77.96 KB 78.07 KB FB_WWW_PROD
react-dom.development.js +0.1% +0.1% 907.44 KB 908.68 KB 205.83 KB 205.94 KB NODE_DEV
ReactDOMForked-profiling.js +0.2% +0.1% 441.66 KB 442.57 KB 79.7 KB 79.81 KB FB_WWW_PROFILING
react-dom-server.browser.development.js 0.0% -0.0% 137.35 KB 137.35 KB 36.47 KB 36.47 KB NODE_DEV
react-dom.production.min.js 🔺+0.2% 🔺+0.2% 125.63 KB 125.82 KB 39.23 KB 39.32 KB NODE_PROD
react-dom-server.browser.production.min.js 0.0% -0.0% 20.26 KB 20.26 KB 7.51 KB 7.51 KB NODE_PROD
react-dom.profiling.min.js +0.1% 0.0% 129.88 KB 130.07 KB 40.55 KB 40.55 KB NODE_PROFILING
ReactDOM-dev.js +0.1% +0.1% 1.02 MB 1.02 MB 231.2 KB 231.33 KB FB_WWW_DEV
ReactDOMServer-dev.js 0.0% -0.0% 144.29 KB 144.29 KB 36.69 KB 36.69 KB FB_WWW_DEV
ReactDOM-prod.js 🔺+0.2% 🔺+0.1% 433.66 KB 434.72 KB 76.95 KB 77.05 KB FB_WWW_PROD
ReactDOMServer-prod.js 0.0% -0.0% 46.58 KB 46.58 KB 10.9 KB 10.9 KB FB_WWW_PROD
ReactDOM-profiling.js +0.2% +0.1% 445.13 KB 446.19 KB 78.85 KB 78.95 KB FB_WWW_PROFILING
react-dom-unstable-fizz.node.development.js 0.0% -0.1% 5.61 KB 5.61 KB 1.87 KB 1.86 KB NODE_DEV
react-dom-unstable-fizz.node.production.min.js 0.0% -0.3% 1.17 KB 1.17 KB 668 B 666 B NODE_PROD
ReactDOMTesting-prod.js 0.0% -0.0% 394.38 KB 394.38 KB 73.01 KB 73.01 KB FB_WWW_PROD
react-dom-test-utils.development.js 0.0% -0.0% 70.47 KB 70.47 KB 19.74 KB 19.74 KB NODE_DEV
react-dom-unstable-fizz.browser.development.js 0.0% -0.1% 4.87 KB 4.87 KB 1.71 KB 1.7 KB NODE_DEV
react-dom-test-utils.production.min.js 0.0% -0.1% 13.06 KB 13.06 KB 4.81 KB 4.8 KB NODE_PROD
react-dom-unstable-fizz.browser.production.min.js 0.0% -0.3% 1.01 KB 1.01 KB 618 B 616 B NODE_PROD
react-dom-server.node.development.js 0.0% -0.0% 138.62 KB 138.62 KB 36.73 KB 36.72 KB NODE_DEV
react-dom-server.node.production.min.js 0.0% -0.0% 20.68 KB 20.68 KB 7.66 KB 7.66 KB NODE_PROD

react-art

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-art.development.js +0.2% +0.1% 669.06 KB 670.37 KB 141.04 KB 141.16 KB UMD_DEV
react-art.production.min.js 🔺+0.2% 🔺+0.3% 111.15 KB 111.35 KB 33.69 KB 33.78 KB UMD_PROD
react-art.development.js +0.2% +0.1% 571.85 KB 573.1 KB 123.3 KB 123.42 KB NODE_DEV
react-art.production.min.js 🔺+0.3% 🔺+0.2% 76.1 KB 76.3 KB 22.84 KB 22.89 KB NODE_PROD
ReactART-dev.js +0.2% +0.1% 608.38 KB 609.72 KB 128.11 KB 128.25 KB FB_WWW_DEV
ReactART-prod.js 🔺+0.4% 🔺+0.2% 242.65 KB 243.71 KB 41.47 KB 41.57 KB FB_WWW_PROD

react-reconciler

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-reconciler.development.js +0.2% +0.1% 629.34 KB 630.59 KB 133.39 KB 133.51 KB NODE_DEV
react-reconciler.production.min.js 🔺+0.2% 🔺+0.2% 85.93 KB 86.13 KB 25.66 KB 25.72 KB NODE_PROD
react-reconciler-reflection.development.js 0.0% -0.0% 17.72 KB 17.72 KB 5.24 KB 5.24 KB NODE_DEV
react-reconciler-reflection.production.min.js 0.0% -0.2% 2.93 KB 2.93 KB 1.22 KB 1.21 KB NODE_PROD

ReactDOM: size: 0.0%, gzip: -0.0%

Size changes (experimental)

Generated by 🚫 dangerJS against 21b624a

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.
@sizebot
Copy link

sizebot commented May 28, 2020

Details of bundled changes.

Comparing: 6071486...21b624a

react-dom

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
ReactDOM-profiling.js +0.2% +0.1% 456.27 KB 457.33 KB 80.71 KB 80.81 KB FB_WWW_PROFILING
react-dom-test-utils.production.min.js 0.0% -0.1% 13.05 KB 13.05 KB 4.8 KB 4.79 KB NODE_PROD
react-dom-server.browser.development.js 0.0% -0.0% 137.42 KB 137.42 KB 35.17 KB 35.16 KB UMD_DEV
react-dom-server.browser.production.min.js 0.0% -0.0% 19.88 KB 19.88 KB 7.45 KB 7.45 KB UMD_PROD
ReactDOMForked-dev.js +0.1% +0.1% 1.04 MB 1.04 MB 238.97 KB 239.11 KB FB_WWW_DEV
ReactDOMForked-prod.js 🔺+0.2% 🔺+0.1% 442.32 KB 443.23 KB 79.83 KB 79.94 KB FB_WWW_PROD
react-dom.development.js 0.0% -0.0% 918.95 KB 918.96 KB 201.86 KB 201.85 KB UMD_DEV
ReactDOMForked-profiling.js +0.2% +0.1% 452.91 KB 453.82 KB 81.6 KB 81.7 KB FB_WWW_PROFILING
react-dom.production.min.js 0.0% -0.0% 120.66 KB 120.66 KB 38.73 KB 38.73 KB UMD_PROD
react-dom.profiling.min.js 0.0% -0.0% 124.65 KB 124.65 KB 39.95 KB 39.95 KB UMD_PROFILING
ReactDOMTesting-dev.js 0.0% -0.0% 963.65 KB 963.65 KB 215.07 KB 215.07 KB FB_WWW_DEV
react-dom.development.js 0.0% -0.0% 874.73 KB 874.73 KB 199.3 KB 199.3 KB NODE_DEV
react-dom-server.node.development.js 0.0% -0.0% 131.63 KB 131.63 KB 34.97 KB 34.97 KB NODE_DEV
react-dom.production.min.js 0.0% -0.0% 120.78 KB 120.78 KB 37.79 KB 37.79 KB NODE_PROD
react-dom-test-utils.development.js 0.0% -0.0% 75.65 KB 75.65 KB 20.23 KB 20.23 KB UMD_DEV
react-dom-server.node.production.min.js 0.0% -0.0% 20.22 KB 20.22 KB 7.59 KB 7.59 KB NODE_PROD
react-dom.profiling.min.js 0.0% -0.0% 124.9 KB 124.9 KB 39.05 KB 39.05 KB NODE_PROFILING
react-dom-test-utils.production.min.js 0.0% -0.0% 13.17 KB 13.17 KB 4.89 KB 4.89 KB UMD_PROD
ReactDOM-dev.js +0.1% +0.1% 1.04 MB 1.04 MB 236.77 KB 236.9 KB FB_WWW_DEV
ReactDOM-prod.js 🔺+0.2% 🔺+0.1% 444.74 KB 445.8 KB 78.79 KB 78.89 KB FB_WWW_PROD
react-dom-test-utils.development.js 0.0% -0.0% 70.46 KB 70.46 KB 19.73 KB 19.73 KB NODE_DEV
react-dom-server.browser.development.js 0.0% -0.0% 130.36 KB 130.36 KB 34.72 KB 34.72 KB NODE_DEV
react-dom-server.browser.production.min.js 0.0% -0.0% 19.8 KB 19.8 KB 7.43 KB 7.43 KB NODE_PROD
ReactDOMServer-dev.js 0.0% -0.0% 148.32 KB 148.32 KB 37.67 KB 37.67 KB FB_WWW_DEV
ReactDOMServer-prod.js 0.0% -0.0% 47.44 KB 47.44 KB 11.11 KB 11.11 KB FB_WWW_PROD

react-art

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
ReactART-dev.js +0.2% +0.1% 618.4 KB 619.74 KB 130.09 KB 130.24 KB FB_WWW_DEV
ReactART-prod.js 🔺+0.4% 🔺+0.2% 249.68 KB 250.74 KB 42.72 KB 42.82 KB FB_WWW_PROD
react-art.development.js 0.0% -0.0% 644.36 KB 644.37 KB 135.86 KB 135.86 KB UMD_DEV
react-art.production.min.js 0.0% -0.0% 107.79 KB 107.79 KB 32.71 KB 32.71 KB UMD_PROD
react-art.development.js 0.0% 0.0% 548.18 KB 548.19 KB 118.28 KB 118.28 KB NODE_DEV
react-art.production.min.js 0.0% -0.0% 72.79 KB 72.79 KB 21.83 KB 21.83 KB NODE_PROD

ReactDOM: size: 0.0%, gzip: -0.0%

Size changes (stable)

Generated by 🚫 dangerJS against 21b624a

@gaearon
Copy link
Collaborator

gaearon commented May 28, 2020

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.

Is that difference in behavior accidental or intentional? (Just curious.)

@sebmarkbage
Copy link
Collaborator Author

sebmarkbage commented May 28, 2020

Is that difference in behavior accidental or intentional?

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.

@sebmarkbage sebmarkbage merged commit 518ce9c into facebook:master May 28, 2020
sebmarkbage added a commit to sebmarkbage/react that referenced this pull request Oct 30, 2020
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.
sebmarkbage added a commit that referenced this pull request Oct 31, 2020
…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.
koto pushed a commit to koto/react that referenced this pull request Jun 15, 2021
…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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed React Core Team Opened by a member of the React Core Team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants