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

[Bugfix] Dropped updates inside a suspended tree #18384

Merged
merged 6 commits into from Mar 26, 2020

Conversation

@acdlite
Copy link
Member

@acdlite acdlite commented Mar 25, 2020

Fixes #18353.

When there are multiple updates at different priority levels inside a suspended subtree, all but the highest priority one is dropped after the highest one suspends.

We do have tests that cover this for updates that originate outside of the Suspense boundary, but not for updates that originate inside.

I'm surprised it's taken us this long to find this issue, but it makes sense in that transition updates usually originate outside the boundary or "seam" of the part of the UI that is transitioning.


This is related to #18353 but it only fixes part of it. There's another bug, which I believe is related to setState traversal skipping over the primary fragment fiber. Still working on that one. Update: yep, that was it. Pushed another commit that and confirmed that it fixes the sandbox in #18353. CodeSandbox CI is currently down, but when it's back up I'll post an updated sandbox.

Also related to #18357, but likewise only fixes part of it.

// TODO: We used to track the lowest pending level for the whole root, but
// we removed it to simplify the implementation. It might be worth adding
// it back for this use case, to avoid redundant passes.
Comment on lines 1612 to 1614

This comment has been minimized.

@acdlite

acdlite Mar 25, 2020
Author Member

@sebmarkbage I think I'm going to do this (add back root.lastPendingTime)

This comment has been minimized.

@sebmarkbage

sebmarkbage Mar 25, 2020
Member

Instead of tracking it globally, why won't we just track it on this suspense boundary in the state?

This comment has been minimized.

@acdlite

acdlite Mar 25, 2020
Author Member

I'm going to track the "suspended time" locally but to track the "last pending time" locally I'd have to add stuff to the setState path. Doesn't seem worth it since the bitmask version will be much simpler.

@sizebot
Copy link

@sizebot sizebot commented Mar 25, 2020

Details of bundled changes.

Comparing: e0ab1a4...ae27d3a

react-test-renderer

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-test-renderer.development.js +0.7% +0.8% 569.07 KB 572.92 KB 118.18 KB 119.08 KB UMD_DEV
react-test-renderer.production.min.js 🔺+0.5% 🔺+0.6% 73.09 KB 73.47 KB 22.29 KB 22.41 KB UMD_PROD
react-test-renderer-shallow.development.js 0.0% 0.0% 38.4 KB 38.4 KB 9.3 KB 9.3 KB UMD_DEV
react-test-renderer.development.js +0.7% +0.8% 542.39 KB 546.11 KB 116.77 KB 117.66 KB NODE_DEV
react-test-renderer.production.min.js 🔺+0.5% 🔺+0.7% 72.9 KB 73.29 KB 21.97 KB 22.11 KB NODE_PROD
ReactTestRenderer-dev.js +0.7% +0.8% 574.7 KB 578.63 KB 121.16 KB 122.1 KB FB_WWW_DEV

react-dom

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-dom.profiling.min.js +0.3% +0.3% 126.22 KB 126.63 KB 39.52 KB 39.64 KB NODE_PROFILING
ReactDOM-dev.js +0.5% +0.4% 957.07 KB 961.39 KB 212.74 KB 213.69 KB FB_WWW_DEV
react-dom-unstable-fizz.browser.production.min.js 0.0% -0.1% 1.19 KB 1.19 KB 699 B 698 B UMD_PROD
ReactDOM-prod.js 🔺+0.6% 🔺+0.4% 396.75 KB 399.09 KB 72.18 KB 72.49 KB FB_WWW_PROD
ReactDOM-profiling.js +0.6% +0.4% 414.34 KB 416.75 KB 75.19 KB 75.49 KB FB_WWW_PROFILING
react-dom-test-utils.development.js 0.0% 0.0% 59.24 KB 59.24 KB 15.65 KB 15.65 KB UMD_DEV
ReactDOMTesting-dev.js +0.5% +0.5% 913.79 KB 918.12 KB 203.96 KB 204.91 KB FB_WWW_DEV
ReactDOMTesting-prod.js 🔺+0.5% 🔺+0.3% 391.41 KB 393.27 KB 71.53 KB 71.77 KB FB_WWW_PROD
react-dom-test-utils.development.js 0.0% 0.0% 54.7 KB 54.7 KB 15.03 KB 15.04 KB NODE_DEV
ReactDOMTesting-profiling.js +0.5% +0.3% 391.41 KB 393.27 KB 71.53 KB 71.77 KB FB_WWW_PROFILING
react-dom.development.js +0.4% +0.5% 933.4 KB 937.6 KB 203.81 KB 204.74 KB UMD_DEV
react-dom.production.min.js 🔺+0.3% 🔺+0.2% 122.09 KB 122.5 KB 39.04 KB 39.14 KB UMD_PROD
ReactDOMForked-dev.js +0.5% +0.4% 957.07 KB 961.39 KB 212.74 KB 213.69 KB FB_WWW_DEV
react-dom-unstable-native-dependencies.production.min.js 0.0% 0.0% 10.32 KB 10.32 KB 3.49 KB 3.5 KB UMD_PROD
react-dom.profiling.min.js +0.3% +0.3% 125.92 KB 126.34 KB 40.28 KB 40.42 KB UMD_PROFILING
ReactDOMForked-prod.js 🔺+0.6% 🔺+0.4% 396.75 KB 399.09 KB 72.18 KB 72.49 KB FB_WWW_PROD
react-dom.development.js +0.5% +0.5% 888.6 KB 892.67 KB 201.33 KB 202.25 KB NODE_DEV
ReactDOMForked-profiling.js +0.6% +0.4% 414.34 KB 416.75 KB 75.19 KB 75.49 KB FB_WWW_PROFILING
react-dom.production.min.js 🔺+0.3% 🔺+0.3% 122.24 KB 122.65 KB 38.24 KB 38.36 KB NODE_PROD
react-dom-unstable-native-dependencies.production.min.js 0.0% 0.0% 10.05 KB 10.05 KB 3.38 KB 3.38 KB NODE_PROD

react-art

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
ReactART-dev.js +0.8% +0.8% 573.58 KB 577.91 KB 120.2 KB 121.17 KB FB_WWW_DEV
ReactART-prod.js 🔺+1.0% 🔺+0.7% 231.91 KB 234.15 KB 39.56 KB 39.84 KB FB_WWW_PROD
react-art.development.js +0.6% +0.7% 651.84 KB 656.04 KB 136.62 KB 137.52 KB UMD_DEV
react-art.production.min.js 🔺+0.4% 🔺+0.4% 108.6 KB 109.01 KB 32.93 KB 33.06 KB UMD_PROD
react-art.development.js +0.7% +0.8% 555.27 KB 559.34 KB 118.98 KB 119.89 KB NODE_DEV
react-art.production.min.js 🔺+0.6% 🔺+0.6% 73.59 KB 73.99 KB 22.08 KB 22.21 KB NODE_PROD

react-native-renderer

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
ReactNativeRenderer-dev.js +0.6% +0.6% 652.37 KB 656.31 KB 140.72 KB 141.61 KB RN_FB_DEV
ReactNativeRenderer-prod.js 🔺+0.8% 🔺+0.7% 266.86 KB 268.98 KB 46.36 KB 46.67 KB RN_FB_PROD
ReactNativeRenderer-profiling.js +0.8% +0.6% 278.65 KB 280.82 KB 48.62 KB 48.93 KB RN_FB_PROFILING
ReactFabric-dev.js +0.6% +0.7% 631.52 KB 635.46 KB 135.96 KB 136.87 KB RN_OSS_DEV
ReactFabric-prod.js 🔺+0.8% 🔺+0.7% 258.7 KB 260.81 KB 44.85 KB 45.16 KB RN_OSS_PROD
ReactFabric-profiling.js +0.8% +0.6% 270.49 KB 272.66 KB 47.11 KB 47.4 KB RN_OSS_PROFILING
ReactFabric-dev.js +0.6% +0.7% 634.24 KB 638.17 KB 136.3 KB 137.19 KB RN_FB_DEV
ReactFabric-prod.js 🔺+0.8% 🔺+0.7% 258.85 KB 260.97 KB 44.88 KB 45.19 KB RN_FB_PROD
ReactNativeRenderer-dev.js +0.6% +0.6% 649.66 KB 653.6 KB 140.37 KB 141.27 KB RN_OSS_DEV
ReactFabric-profiling.js +0.8% +0.6% 270.64 KB 272.8 KB 47.13 KB 47.43 KB RN_FB_PROFILING
ReactNativeRenderer-prod.js 🔺+0.8% 🔺+0.7% 266.71 KB 268.83 KB 46.33 KB 46.64 KB RN_OSS_PROD
ReactNativeRenderer-profiling.js +0.8% +0.6% 278.51 KB 280.67 KB 48.59 KB 48.9 KB RN_OSS_PROFILING

react-reconciler

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-reconciler.development.js +0.7% +0.7% 595.64 KB 599.71 KB 125.29 KB 126.21 KB NODE_DEV
react-reconciler.production.min.js 🔺+0.5% 🔺+0.5% 78.82 KB 79.23 KB 23.21 KB 23.34 KB NODE_PROD

Size changes (experimental)

Generated by 🚫 dangerJS against ae27d3a

@sizebot
Copy link

@sizebot sizebot commented Mar 25, 2020

Details of bundled changes.

Comparing: e0ab1a4...ae27d3a

react-dom

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-dom.production.min.js 🔺+0.3% 🔺+0.3% 118.17 KB 118.55 KB 37.13 KB 37.26 KB NODE_PROD
react-dom-test-utils.development.js 0.0% 0.0% 59.23 KB 59.23 KB 15.64 KB 15.64 KB UMD_DEV
ReactDOMTesting-profiling.js +0.5% +0.4% 403.86 KB 406.01 KB 73.47 KB 73.77 KB FB_WWW_PROFILING
react-dom.profiling.min.js +0.3% +0.3% 122.02 KB 122.41 KB 38.32 KB 38.43 KB NODE_PROFILING
react-dom-unstable-fizz.browser.production.min.js 0.0% -0.1% 1.17 KB 1.17 KB 691 B 690 B UMD_PROD
ReactDOMForked-dev.js +0.4% +0.4% 1002.92 KB 1007.25 KB 222.78 KB 223.73 KB FB_WWW_DEV
ReactDOMForked-prod.js 🔺+0.5% 🔺+0.4% 422.61 KB 424.77 KB 76.68 KB 77 KB FB_WWW_PROD
react-dom.development.js +0.4% +0.5% 903.61 KB 907.46 KB 198.59 KB 199.49 KB UMD_DEV
ReactDOMForked-profiling.js +0.5% +0.4% 440.25 KB 442.48 KB 79.77 KB 80.06 KB FB_WWW_PROFILING
react-dom.production.min.js 🔺+0.3% 🔺+0.4% 118.09 KB 118.48 KB 37.88 KB 38.03 KB UMD_PROD
react-dom.profiling.min.js +0.3% +0.3% 121.8 KB 122.19 KB 39.12 KB 39.22 KB UMD_PROFILING
ReactDOMTesting-dev.js +0.5% +0.5% 940.55 KB 944.88 KB 209.86 KB 210.81 KB FB_WWW_DEV
react-dom.development.js +0.4% +0.4% 860.04 KB 863.77 KB 196.17 KB 197.04 KB NODE_DEV
ReactDOMTesting-prod.js 🔺+0.5% 🔺+0.4% 403.86 KB 406.01 KB 73.47 KB 73.77 KB FB_WWW_PROD
react-dom-server.browser.development.js 0.0% -0.0% 126.32 KB 126.32 KB 33.84 KB 33.83 KB NODE_DEV
ReactDOM-dev.js +0.4% +0.4% 1002.92 KB 1007.25 KB 222.78 KB 223.73 KB FB_WWW_DEV
ReactDOM-prod.js 🔺+0.5% 🔺+0.4% 422.61 KB 424.77 KB 76.68 KB 77 KB FB_WWW_PROD
react-dom-test-utils.development.js 0.0% 0.0% 54.69 KB 54.69 KB 15.03 KB 15.03 KB NODE_DEV
ReactDOM-profiling.js +0.5% +0.4% 440.25 KB 442.48 KB 79.77 KB 80.06 KB FB_WWW_PROFILING
react-dom-unstable-native-dependencies.production.min.js 0.0% 0.0% 10.31 KB 10.31 KB 3.49 KB 3.49 KB UMD_PROD
react-dom-unstable-native-dependencies.production.min.js 0.0% 0.0% 10.04 KB 10.04 KB 3.37 KB 3.37 KB NODE_PROD

react-native-renderer

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
ReactNativeRenderer-dev.js +0.6% +0.6% 649.65 KB 653.59 KB 140.37 KB 141.27 KB RN_OSS_DEV
ReactNativeRenderer-prod.js 🔺+0.8% 🔺+0.7% 266.7 KB 268.82 KB 46.32 KB 46.63 KB RN_OSS_PROD
ReactNativeRenderer-profiling.js +0.8% +0.6% 278.5 KB 280.66 KB 48.58 KB 48.89 KB RN_OSS_PROFILING
ReactFabric-dev.js +0.6% +0.7% 631.51 KB 635.45 KB 135.96 KB 136.86 KB RN_OSS_DEV
ReactFabric-prod.js 🔺+0.8% 🔺+0.7% 258.68 KB 260.8 KB 44.85 KB 45.16 KB RN_OSS_PROD
ReactFabric-profiling.js +0.8% +0.6% 270.48 KB 272.64 KB 47.1 KB 47.39 KB RN_OSS_PROFILING

react-art

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-art.development.js +0.7% +0.8% 535.8 KB 539.52 KB 115.29 KB 116.18 KB NODE_DEV
react-art.production.min.js 🔺+0.5% 🔺+0.8% 71.08 KB 71.47 KB 21.4 KB 21.57 KB NODE_PROD
ReactART-dev.js +0.7% +0.8% 601.65 KB 605.98 KB 125.87 KB 126.85 KB FB_WWW_DEV
ReactART-prod.js 🔺+0.9% 🔺+0.7% 240.95 KB 243.07 KB 40.97 KB 41.26 KB FB_WWW_PROD
react-art.development.js +0.6% +0.7% 631.57 KB 635.42 KB 132.95 KB 133.82 KB UMD_DEV
react-art.production.min.js 🔺+0.4% 🔺+0.3% 106.04 KB 106.43 KB 32.2 KB 32.3 KB UMD_PROD

react-test-renderer

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-test-renderer-shallow.development.js 0.0% 0.0% 38.39 KB 38.39 KB 9.29 KB 9.29 KB UMD_DEV
react-test-renderer.development.js +0.7% +0.8% 542.36 KB 546.09 KB 116.76 KB 117.65 KB NODE_DEV
react-test-renderer.production.min.js 🔺+0.5% 🔺+0.7% 72.88 KB 73.26 KB 21.95 KB 22.09 KB NODE_PROD
ReactTestRenderer-dev.js +0.7% +0.8% 574.68 KB 578.62 KB 121.15 KB 122.09 KB FB_WWW_DEV
react-test-renderer.development.js +0.7% +0.8% 569.04 KB 572.89 KB 118.17 KB 119.07 KB UMD_DEV
react-test-renderer.production.min.js 🔺+0.5% 🔺+0.6% 73.06 KB 73.44 KB 22.27 KB 22.39 KB UMD_PROD

react-reconciler

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-reconciler.development.js +0.6% +0.7% 573.83 KB 577.56 KB 121.08 KB 121.98 KB NODE_DEV
react-reconciler-reflection.development.js 0.0% 0.0% 15.55 KB 15.55 KB 4.73 KB 4.73 KB NODE_DEV
react-reconciler.production.min.js 🔺+0.5% 🔺+0.6% 75.92 KB 76.31 KB 22.5 KB 22.64 KB NODE_PROD

Size changes (stable)

Generated by 🚫 dangerJS against ae27d3a

@acdlite acdlite force-pushed the acdlite:bugfix-dropped-updates-in branch from 602a821 to 1b3bc39 Mar 25, 2020
//
// As a workaround, we need to recompute the `childExpirationTime`
// by bubbling it up from the next level of children. This is
// based on similar logic in `resetChildExpirationTime`.

This comment has been minimized.

@acdlite

acdlite Mar 25, 2020
Author Member

An alternative fix would be to detect this during setState. I thought it might be better to localize the fix here since it's relatively rare but I'm having second thoughts.

This comment has been minimized.

@sebmarkbage

sebmarkbage Mar 25, 2020
Member

I think this is the right call to keep it in the rare path.

I think we should just bite the bullet have have Suspense boundaries always have these fragments even when not suspended. It's too much code to manage (buggy and byte size). Especially with enter/exit animations it's going to get even trickier.

It adds a bit more memory but there's not that many suspense boundaries and the ones that do exist fairly often transition through this state anyway.

This comment has been minimized.

@acdlite

acdlite Mar 25, 2020
Author Member

That would definitely simplify things a lot

@gaearon
Copy link
Member

@gaearon gaearon commented Mar 25, 2020

Is it worth adding tests for similar scenarios but with updates originating inside the fallback just in case?

acdlite added 5 commits Mar 20, 2020
Adds a `resolveText` method as an alternative to using timers. Also
removes dependency on react-cache (for just this one test file; can do
the others later).

Timer option is still there if you provide a `ms` prop.
When there are multiple updates at different priority levels inside
a suspended subtree, all but the highest priority one is dropped after
the highest one suspends.

We do have tests that cover this for updates that originate outside of
the Suspense boundary, but not for updates that originate inside.

I'm surprised it's taken us this long to find this issue, but it makes
sense in that transition updates usually originate outside the boundary
or "seam" of the part of the UI that is transitioning.
Fixes a bug where updates inside a suspended tree are dropped because
the fragment fiber we insert to wrap the hidden children is not part of
the return path, so it doesn't get marked during setState.

As a workaround, I recompute `childExpirationTime` right before deciding
to bail out by bubbling it up from the next level of children.

This is something we should consider addressing when we refactor the
Fiber data structure.
This reverts commit 9a54113.

I want to use this so we can check if there might be any lower priority
updates in a suspended tree.

We can remove it again during the expiration times refactor.
We don't currently have an mechanism to check if there are lower
priority updates in a subtree, but we can check if there are any in the
whole root. This still isn't perfect but it's better than using Idle,
which frequently leads to redundant re-renders.

When we refactor `expirationTime` to be a bitmask, this will no longer
be necessary because we'll know exactly which "task bits" remain.
@acdlite acdlite force-pushed the acdlite:bugfix-dropped-updates-in branch from 1b3bc39 to 4ffc49a Mar 26, 2020
@codesandbox
Copy link

@codesandbox codesandbox bot commented Mar 26, 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 ae27d3a:

Sandbox Source
nervous-nightingale-o3tdv Configuration
great-waterfall-z2wlu Issue #18353
@acdlite acdlite force-pushed the acdlite:bugfix-dropped-updates-in branch from e54aeb9 to ae27d3a Mar 26, 2020
@acdlite
Copy link
Member Author

@acdlite acdlite commented Mar 26, 2020

Added a fallback test case

@acdlite acdlite merged commit 9d67847 into facebook:master Mar 26, 2020
31 checks passed
31 checks passed
ci/circleci: NODE_ENV_production_yarn_test_www Your tests passed on CircleCI!
Details
ci/circleci: NODE_ENV_production_yarn_test_www_variant Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_NODE_ENV_production_yarn_test_www Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_NODE_ENV_production_yarn_test_www_variant Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_build Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_test Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_test_build Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_test_build_prod Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_test_dom_fixtures Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_test_persistent Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_test_prod Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_test_www Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_test_www_variant Your tests passed on CircleCI!
Details
ci/circleci: build_devtools_and_process_artifacts Your tests passed on CircleCI!
Details
ci/circleci: process_artifacts Your tests passed on CircleCI!
Details
ci/circleci: process_artifacts_experimental Your tests passed on CircleCI!
Details
ci/circleci: setup Your tests passed on CircleCI!
Details
ci/circleci: sizebot_experimental Your tests passed on CircleCI!
Details
ci/circleci: sizebot_stable Your tests passed on CircleCI!
Details
ci/circleci: yarn_build Your tests passed on CircleCI!
Details
ci/circleci: yarn_flow Your tests passed on CircleCI!
Details
ci/circleci: yarn_lint Your tests passed on CircleCI!
Details
ci/circleci: yarn_lint_build Your tests passed on CircleCI!
Details
ci/circleci: yarn_test Your tests passed on CircleCI!
Details
ci/circleci: yarn_test_build Your tests passed on CircleCI!
Details
ci/circleci: yarn_test_build_devtools Your tests passed on CircleCI!
Details
ci/circleci: yarn_test_build_prod Your tests passed on CircleCI!
Details
ci/circleci: yarn_test_prod Your tests passed on CircleCI!
Details
ci/circleci: yarn_test_www Your tests passed on CircleCI!
Details
ci/circleci: yarn_test_www_variant Your tests passed on CircleCI!
Details
ci/codesandbox Building packages succeeded.
Details
acdlite added a commit that referenced this pull request Mar 27, 2020
This assignment should have been deleted in #18384. It was deleted in
the other branches, but I missed this one. About to open a PR that
includes a test that covers this branch.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

5 participants
You can’t perform that action at this time.