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

Deal with fallback content in Partial Hydration #14884

Merged
merged 4 commits into from
Feb 19, 2019

Conversation

sebmarkbage
Copy link
Collaborator

Previously we assumed that we hydrated only once we had the final content in the suspense boundary. This lets a dehydrated suspense boundary to be in three possible states (as encoded with different comment nodes):

Pending <!--$?--> - In the pending state, we assume that the content is displaying the fallback state and we're not yet to hydrate because the streaming server (Fizz) will send the content later on. In this state, React won't try to hydrate the content. If props or context changes, the boundary will be deleted and replaced. React will register a ._reactRetry function on the comment node which is expected to be invoked when this boundary changes to one of the other two states.

Fallback <!--$!--> - In the fallback state, we assume that the content is displaying the fallback state and that it is fine to keep displaying that but we won't get anything more from the server. Therefore, React is now free to replace it with the final content by rendering it on the client instead.

Success <!--$--> - In this state, we assume that the content of the boundary is the final content and will be the same as if we rendered the content on the client so we can now start hydrating it.

In the current server renderer we always render suspended boundaries as "Fallback". This is useful for content that you only want to render on the client.

In Fizz, this PR lets hydration start before the final content is resolved.

It is possible that the server will eventually error and not be able to send the final content. If that happens, or a timeout, the Fizz runtime is expected to switch the pending state to fallback state. This lets the client try to render it, and if it errors again, replace it with error boundary content.

I had thought that we could always try to render the content on the client if we could. However, that didn't work out. For one, it's a waste of cycles since you're most likely going to suspend anyway since you're unlikely to have all the data sent down the wire yet. More importantly, if the client succeeds, it might still have further nested fallback states that the server wouldn't have had. So it might be better to show the server content anyway. In theory we could try to patch up new server content but that seems complicated and breaks the clean architectural boundary between Fizz and the client.

@sizebot
Copy link

sizebot commented Feb 19, 2019

ReactDOM: size: 0.0%, gzip: 0.0%

Details of bundled changes.

Comparing: 0e67969...6d626fb

react-dom

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-dom.development.js +0.3% +0.4% 765.35 KB 767.8 KB 174.45 KB 175.17 KB UMD_DEV
react-dom.production.min.js 0.0% 0.0% 105.34 KB 105.34 KB 33.94 KB 33.95 KB UMD_PROD
react-dom.profiling.min.js 0.0% 0.0% 108.26 KB 108.26 KB 34.82 KB 34.82 KB UMD_PROFILING
react-dom.development.js +0.3% +0.4% 759.95 KB 762.41 KB 172.96 KB 173.67 KB NODE_DEV
react-dom.production.min.js 0.0% 0.0% 105.5 KB 105.51 KB 33.43 KB 33.43 KB NODE_PROD
react-dom.profiling.min.js 0.0% 0.0% 108.58 KB 108.58 KB 34.25 KB 34.25 KB NODE_PROFILING
ReactDOM-dev.js +0.3% +0.4% 782.94 KB 785.48 KB 174.19 KB 174.87 KB FB_WWW_DEV
ReactDOM-prod.js 🔺+0.2% 🔺+0.2% 321.54 KB 322.29 KB 58.61 KB 58.74 KB FB_WWW_PROD
ReactDOM-profiling.js +0.2% +0.2% 328.11 KB 328.87 KB 60.09 KB 60.21 KB FB_WWW_PROFILING
react-dom-unstable-fire.development.js +0.3% +0.4% 765.7 KB 768.15 KB 174.59 KB 175.31 KB UMD_DEV
react-dom-unstable-fire.production.min.js 0.0% 0.0% 105.35 KB 105.36 KB 33.95 KB 33.95 KB UMD_PROD
react-dom-unstable-fire.profiling.min.js 0.0% 0.0% 108.27 KB 108.28 KB 34.83 KB 34.83 KB UMD_PROFILING
react-dom-unstable-fire.development.js +0.3% +0.4% 760.3 KB 762.75 KB 173.1 KB 173.82 KB NODE_DEV
react-dom-unstable-fire.production.min.js 0.0% 0.0% 105.52 KB 105.52 KB 33.44 KB 33.44 KB NODE_PROD
react-dom-unstable-fire.profiling.min.js 0.0% 0.0% 108.59 KB 108.59 KB 34.26 KB 34.26 KB NODE_PROFILING
ReactFire-dev.js +0.3% +0.4% 782.15 KB 784.69 KB 174.11 KB 174.82 KB FB_WWW_DEV
ReactFire-prod.js 🔺+0.2% 🔺+0.2% 309.96 KB 310.72 KB 56.29 KB 56.41 KB FB_WWW_PROD
ReactFire-profiling.js +0.2% +0.2% 316.58 KB 317.33 KB 57.7 KB 57.82 KB FB_WWW_PROFILING
react-dom-test-utils.production.min.js 0.0% -0.1% 10.27 KB 10.27 KB 3.8 KB 3.8 KB UMD_PROD
react-dom-test-utils.development.js 0.0% -0.0% 46.78 KB 46.78 KB 12.92 KB 12.92 KB NODE_DEV
react-dom-server.browser.development.js 0.0% 0.0% 127.18 KB 127.21 KB 33.88 KB 33.88 KB UMD_DEV
react-dom-server.browser.production.min.js 🔺+0.2% 🔺+0.1% 18.85 KB 18.89 KB 7.21 KB 7.22 KB UMD_PROD
react-dom-server.browser.development.js 0.0% 0.0% 123.31 KB 123.35 KB 32.94 KB 32.95 KB NODE_DEV
react-dom-server.browser.production.min.js 🔺+0.2% 🔺+0.1% 18.77 KB 18.81 KB 7.2 KB 7.21 KB NODE_PROD
ReactDOMServer-dev.js 0.0% 0.0% 124.25 KB 124.29 KB 32.45 KB 32.46 KB FB_WWW_DEV
ReactDOMServer-prod.js 🔺+0.1% 🔺+0.1% 45.22 KB 45.27 KB 10.42 KB 10.43 KB FB_WWW_PROD
react-dom-server.node.development.js 0.0% 0.0% 125.37 KB 125.4 KB 33.48 KB 33.49 KB NODE_DEV
react-dom-server.node.production.min.js 🔺+0.2% 🔺+0.1% 19.65 KB 19.69 KB 7.51 KB 7.52 KB NODE_PROD

react-art

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-art.development.js +0.4% +0.5% 541.95 KB 543.88 KB 117.78 KB 118.39 KB UMD_DEV
react-art.production.min.js 0.0% 0.0% 97.34 KB 97.34 KB 29.88 KB 29.88 KB UMD_PROD
react-art.development.js +0.4% +0.6% 473 KB 474.94 KB 100.55 KB 101.16 KB NODE_DEV
ReactART-dev.js +0.4% +0.6% 482.31 KB 484.27 KB 99.86 KB 100.43 KB FB_WWW_DEV
ReactART-prod.js 🔺+0.2% 🔺+0.2% 195.04 KB 195.51 KB 33.01 KB 33.08 KB FB_WWW_PROD

react-native-renderer

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
ReactNativeRenderer-dev.js +0.3% +0.5% 606.85 KB 608.81 KB 130.22 KB 130.81 KB RN_FB_DEV
ReactNativeRenderer-prod.js -0.0% -0.0% 246.21 KB 246.21 KB 43.01 KB 43.01 KB RN_FB_PROD
ReactNativeRenderer-profiling.js -0.0% -0.0% 252.56 KB 252.56 KB 44.57 KB 44.56 KB RN_FB_PROFILING
ReactNativeRenderer-dev.js +0.3% +0.5% 606.76 KB 608.72 KB 130.18 KB 130.78 KB RN_OSS_DEV
ReactNativeRenderer-prod.js -0.0% -0.0% 246.23 KB 246.23 KB 43.01 KB 43.01 KB RN_OSS_PROD
ReactNativeRenderer-profiling.js -0.0% -0.0% 252.58 KB 252.58 KB 44.56 KB 44.56 KB RN_OSS_PROFILING
ReactFabric-dev.js +0.3% +0.5% 597.7 KB 599.66 KB 127.94 KB 128.53 KB RN_FB_DEV
ReactFabric-profiling.js 0.0% 0.0% 244.79 KB 244.79 KB 43.07 KB 43.07 KB RN_FB_PROFILING
ReactFabric-dev.js +0.3% +0.5% 597.61 KB 599.57 KB 127.89 KB 128.49 KB RN_OSS_DEV
ReactFabric-prod.js 0.0% -0.0% 238.56 KB 238.56 KB 41.54 KB 41.54 KB RN_OSS_PROD
ReactFabric-profiling.js 0.0% 0.0% 244.8 KB 244.8 KB 43.07 KB 43.07 KB RN_OSS_PROFILING

react-test-renderer

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-test-renderer.development.js +0.4% +0.6% 485.08 KB 487.01 KB 102.93 KB 103.54 KB UMD_DEV
react-test-renderer.production.min.js 0.0% 0.0% 63.75 KB 63.75 KB 19.53 KB 19.54 KB UMD_PROD
react-test-renderer.development.js +0.4% +0.6% 479.51 KB 481.45 KB 101.62 KB 102.23 KB NODE_DEV
react-test-renderer.production.min.js 0.0% -0.0% 63.41 KB 63.41 KB 19.21 KB 19.21 KB NODE_PROD
ReactTestRenderer-dev.js +0.4% +0.6% 489.57 KB 491.53 KB 101.28 KB 101.85 KB FB_WWW_DEV
react-test-renderer-shallow.development.js 0.0% -0.0% 31.5 KB 31.5 KB 8.14 KB 8.14 KB NODE_DEV

react-reconciler

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-reconciler.development.js +0.4% +0.6% 470.3 KB 472.34 KB 98.89 KB 99.52 KB NODE_DEV
react-reconciler.production.min.js 0.0% 🔺+0.1% 63.6 KB 63.61 KB 18.81 KB 18.83 KB NODE_PROD
react-reconciler-persistent.development.js +0.4% +0.6% 468.68 KB 470.72 KB 98.25 KB 98.88 KB NODE_DEV
react-reconciler-persistent.production.min.js 0.0% 🔺+0.1% 63.61 KB 63.62 KB 18.82 KB 18.83 KB NODE_PROD

Generated by 🚫 dangerJS

This introduces three states for dehydrated suspense boundaries

Pending - This means that the tree is still waiting for additional data or
to be populated with its final content.

Fallback - This means that the tree has entered a permanent fallback state
and no more data from the server is to be expected. This means that the
client should take over and try to render instead. The fallback nodes will
be deleted.

Normal - The node has entered its final content and is now ready to be
hydrated.
This doesn't just retry. It assumes that resolving a thenable means that
it is ok to clear it from the thenable cache.

We'll reuse the retryTimedOutBoundary logic separately.
…ding

It's now possible to switch from a pending state to either hydrating
or replacing the content.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants