Skip to content

[RN] experiment to move Fabric completeWork to the commit phase #30513

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

Merged
merged 1 commit into from
Jul 29, 2024

Conversation

kassens
Copy link
Member

@kassens kassens commented Jul 29, 2024

There is currently a mismatch in how the persistent mode JS API and the Fabric native code interpret completeRoot.

This is a short-lived experiment to see the effect of moving the Fabric completeRoot call from finalizeContainerChildren to replaceContainerChildren which in some cases does not get called.

Copy link

vercel bot commented Jul 29, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
react-compiler-playground ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 29, 2024 10:12pm

@react-sizebot
Copy link

react-sizebot commented Jul 29, 2024

Comparing: 87b1a94...c518910

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.js = 6.68 kB 6.68 kB = 1.83 kB 1.83 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 501.46 kB 501.46 kB = 89.98 kB 89.98 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 6.69 kB 6.69 kB = 1.83 kB 1.83 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js = 508.59 kB 508.59 kB = 91.15 kB 91.15 kB
facebook-www/ReactDOM-prod.classic.js = 596.53 kB 596.53 kB = 105.80 kB 105.80 kB
facebook-www/ReactDOM-prod.modern.js = 572.82 kB 572.82 kB = 102.01 kB 102.01 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
react-native/implementations/ReactFabric-prod.fb.js +0.29% 363.34 kB 364.38 kB +0.25% 63.98 kB 64.14 kB
react-native/implementations/ReactFabric-profiling.fb.js +0.26% 390.86 kB 391.88 kB +0.30% 68.23 kB 68.44 kB

Generated by 🚫 dangerJS against b102cb0

@facebook-github-bot facebook-github-bot added the React Core Team Opened by a member of the React Core Team label Jul 29, 2024
@kassens kassens changed the title @nocommit test moving completeRoot to replaceContainerChildren [RN] experiment moving Fabric completeWork to the commit phase Jul 29, 2024
@kassens kassens marked this pull request as ready for review July 29, 2024 22:08
@kassens kassens changed the title [RN] experiment moving Fabric completeWork to the commit phase [RN] experiment to move Fabric completeWork to the commit phase Jul 29, 2024
@kassens kassens requested review from sammy-SC and josephsavona July 29, 2024 22:25
Copy link
Member

@josephsavona josephsavona left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is intended for quick experimentation to see if this causes obvious issues, so let's ship and get data to decide next steps. If this works then we can explore the approach @sebmarkbage suggested of potentially splitting up the work of completeRoot() with layout happening in finalizeContainerChildren() and actual committing the tree in replaceContainerChildren().

But we should also consider whether we even need to render and layout the fallback if we're never going to show it, it seems like we may not need that anymore in this case.

@kassens kassens merged commit 6b82f3c into facebook:main Jul 29, 2024
365 checks passed
@kassens kassens deleted the pr30513 branch July 29, 2024 22:38
github-actions bot pushed a commit that referenced this pull request Jul 29, 2024
There is currently a mismatch in how the persistent mode JS API and the
Fabric native code interpret `completeRoot`.

This is a short-lived experiment to see the effect of moving the Fabric
`completeRoot` call from `finalizeContainerChildren` to
`replaceContainerChildren` which in some cases does not get called.

DiffTrain build for commit 6b82f3c.
josephsavona added a commit to josephsavona/react that referenced this pull request Jul 30, 2024
Work-in-progress idea targeting the same situation as facebook#30513.

In React Native, we've found a bug with suspense boundaries reverting to the fallback in the following case. The expected behavior (and behavior on web) is as follows:
1. Render a Suspense boundary on initial mount, resolve the promise, show the content.
2. In a transition, update the content of the existing Suspense boundary, suspending again.
3. The UI should continue to show the previous content
4. Resolve the promise, update to the new content.

However on RN, step 3 shows the fallback again. This is unexpected since we're in a transition and the fallback has already revealed.

What's happening is that in step 3 we call completeWork() which in turn calls finalizeContainerChildren(), which updates to use the fallback. However, this isn't committed to the screen since we never call commitRoot() (and therefore don't call replaceContainerChildren()). Instead, we detec that the render exited with status RootSuspendedOnDelay and that the lane was transition-only, so we don't actually commit the fallback.

However, RN currently commits the content it gets in finalizeContainerChildren(), rather than waiting for replaceContainerChildren() from commitRoot(). The original intent was for finalize...() to do layout, and for replace...() to actually commit the updated tree, which would preserve the web behavior.

facebook#30513 is a brute force way to address this by simply moving all the native work from finalize -> replace. What i'm experimenting with in this PR is to skip calling finalizeContainerChildren() if the above conditions hold: if this is a suspended render in a transition, don't bother finalizing children.
josephsavona added a commit to josephsavona/react that referenced this pull request Jul 30, 2024
Work-in-progress idea targeting the same situation as facebook#30513.

In React Native, we've found a bug with suspense boundaries reverting to the fallback in the following case. The expected behavior (and behavior on web) is as follows:
1. Render a Suspense boundary on initial mount, resolve the promise, show the content.
2. In a transition, update the content of the existing Suspense boundary, suspending again.
3. The UI should continue to show the previous content
4. Resolve the promise, update to the new content.

However on RN, step 3 shows the fallback again. This is unexpected since we're in a transition and the fallback has already revealed.

What's happening is that in step 3 we call completeWork() which in turn calls finalizeContainerChildren(), which updates to use the fallback. However, this isn't committed to the screen since we never call commitRoot() (and therefore don't call replaceContainerChildren()). Instead, we detec that the render exited with status RootSuspendedOnDelay and that the lane was transition-only, so we don't actually commit the fallback.

However, RN currently commits the content it gets in finalizeContainerChildren(), rather than waiting for replaceContainerChildren() from commitRoot(). The original intent was for finalize...() to do layout, and for replace...() to actually commit the updated tree, which would preserve the web behavior.

facebook#30513 is a brute force way to address this by simply moving all the native work from finalize -> replace. What i'm experimenting with in this PR is to skip calling finalizeContainerChildren() if the above conditions hold: if this is a suspended render in a transition, don't bother finalizing children.
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.

4 participants