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

Fix: Synchronous popstate transitions #30759

Merged
merged 1 commit into from
Aug 23, 2024

Conversation

acdlite
Copy link
Collaborator

@acdlite acdlite commented Aug 20, 2024

This is a refactor of the fix in #27505.

When a transition update is scheduled by a popstate event, (i.e. a back/ forward navigation) we attempt to render it synchronously even though it's a transition, since it's likely the previous page's data is cached.

In #27505, I changed the implementation so that it only "upgrades" the priority of the transition for a single attempt. If the attempt suspends, say because the data is not cached after all, from then on it should be treated as a normal transition.

But it turns out #27505 did not work as intended, because it relied on marking the root with pending synchronous work (root.pendingLanes), which was never cleared until the popstate update completed.

The test scenarios I wrote accidentally worked for a different reason related to suspending the work loop, which I'm currently in the middle of refactoring.

Copy link

vercel bot commented Aug 20, 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 Aug 23, 2024 3:58pm

@react-sizebot
Copy link

react-sizebot commented Aug 20, 2024

Comparing: b57d282...7dd999a

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.82 kB
oss-stable/react-dom/cjs/react-dom-client.production.js +0.21% 500.37 kB 501.40 kB +0.21% 89.80 kB 89.99 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 +0.20% 507.50 kB 508.52 kB +0.21% 90.96 kB 91.16 kB
facebook-www/ReactDOM-prod.classic.js +0.15% 595.24 kB 596.16 kB +0.13% 105.55 kB 105.70 kB
facebook-www/ReactDOM-prod.modern.js +0.16% 571.54 kB 572.44 kB +0.13% 101.75 kB 101.88 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable-rc/react-art/cjs/react-art.production.js +0.35% 291.05 kB 292.08 kB +0.30% 50.22 kB 50.38 kB
oss-stable-semver/react-art/cjs/react-art.production.js +0.35% 291.05 kB 292.08 kB +0.30% 50.22 kB 50.38 kB
oss-stable/react-art/cjs/react-art.production.js +0.35% 291.11 kB 292.14 kB +0.30% 50.24 kB 50.40 kB
oss-experimental/react-art/cjs/react-art.production.js +0.34% 298.06 kB 299.09 kB +0.30% 51.45 kB 51.61 kB
oss-stable-rc/react-test-renderer/cjs/react-test-renderer.production.js +0.34% 300.23 kB 301.26 kB +0.34% 53.34 kB 53.52 kB
oss-stable-semver/react-test-renderer/cjs/react-test-renderer.production.js +0.34% 300.23 kB 301.26 kB +0.34% 53.34 kB 53.52 kB
oss-stable/react-test-renderer/cjs/react-test-renderer.production.js +0.34% 300.29 kB 301.32 kB +0.34% 53.36 kB 53.54 kB
oss-experimental/react-test-renderer/cjs/react-test-renderer.production.js +0.34% 302.70 kB 303.73 kB +0.32% 53.83 kB 54.00 kB
facebook-react-native/react-test-renderer/cjs/ReactTestRenderer-prod.js +0.32% 317.72 kB 318.75 kB +0.30% 56.26 kB 56.43 kB
facebook-react-native/react-test-renderer/cjs/ReactTestRenderer-profiling.js +0.30% 341.68 kB 342.71 kB +0.28% 59.73 kB 59.90 kB
react-native/implementations/ReactFabric-prod.js +0.30% 345.57 kB 346.60 kB +0.26% 60.76 kB 60.92 kB
facebook-www/ReactART-prod.modern.js +0.30% 345.26 kB 346.28 kB +0.25% 58.83 kB 58.98 kB
react-native/implementations/ReactNativeRenderer-prod.js +0.29% 354.91 kB 355.94 kB +0.25% 62.36 kB 62.52 kB
facebook-www/ReactART-prod.classic.js +0.28% 362.26 kB 363.29 kB +0.22% 61.60 kB 61.74 kB
react-native/implementations/ReactFabric-prod.fb.js +0.28% 371.64 kB 372.67 kB +0.25% 65.02 kB 65.19 kB
react-native/implementations/ReactFabric-profiling.js +0.27% 372.95 kB 373.97 kB +0.25% 64.87 kB 65.03 kB
react-native/implementations/ReactNativeRenderer-prod.fb.js +0.27% 376.86 kB 377.88 kB +0.23% 66.15 kB 66.31 kB
react-native/implementations/ReactNativeRenderer-profiling.js +0.27% 382.22 kB 383.25 kB +0.24% 66.60 kB 66.76 kB
react-native/implementations/ReactFabric-profiling.fb.js +0.26% 399.18 kB 400.22 kB +0.26% 69.31 kB 69.49 kB
react-native/implementations/ReactNativeRenderer-profiling.fb.js +0.26% 404.37 kB 405.41 kB +0.21% 70.41 kB 70.56 kB
oss-stable-rc/react-reconciler/cjs/react-reconciler.production.js +0.25% 376.50 kB 377.45 kB +0.25% 61.98 kB 62.13 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler.production.js +0.25% 376.50 kB 377.45 kB +0.25% 61.98 kB 62.13 kB
oss-stable/react-reconciler/cjs/react-reconciler.production.js +0.25% 376.53 kB 377.47 kB +0.25% 62.00 kB 62.15 kB
oss-experimental/react-reconciler/cjs/react-reconciler.production.js +0.25% 384.32 kB 385.27 kB +0.24% 63.26 kB 63.41 kB
oss-stable-rc/react-reconciler/cjs/react-reconciler.profiling.js +0.24% 404.88 kB 405.85 kB +0.26% 66.01 kB 66.18 kB
oss-stable-semver/react-reconciler/cjs/react-reconciler.profiling.js +0.24% 404.88 kB 405.85 kB +0.26% 66.01 kB 66.18 kB
oss-stable/react-reconciler/cjs/react-reconciler.profiling.js +0.24% 404.91 kB 405.87 kB +0.23% 66.05 kB 66.20 kB
oss-experimental/react-reconciler/cjs/react-reconciler.profiling.js +0.23% 412.76 kB 413.71 kB +0.21% 67.39 kB 67.54 kB
facebook-www/ReactReconciler-prod.modern.js +0.22% 437.01 kB 437.96 kB +0.22% 71.25 kB 71.41 kB
facebook-www/ReactReconciler-prod.classic.js +0.21% 455.76 kB 456.72 kB +0.21% 74.03 kB 74.18 kB
oss-stable-rc/react-dom/cjs/react-dom-client.production.js +0.21% 500.27 kB 501.29 kB +0.21% 89.78 kB 89.96 kB
oss-stable-semver/react-dom/cjs/react-dom-client.production.js +0.21% 500.27 kB 501.29 kB +0.21% 89.78 kB 89.96 kB
oss-stable/react-dom/cjs/react-dom-client.production.js +0.21% 500.37 kB 501.40 kB +0.21% 89.80 kB 89.99 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js +0.20% 507.50 kB 508.52 kB +0.21% 90.96 kB 91.16 kB

Generated by 🚫 dangerJS against ac17c69

This is a refactor of the fix in facebook#27505.

When a transition update is scheduled by a popstate event, (i.e. a back/
forward navigation) we attempt to render it synchronously even though
it's a transition, since it's likely the previous page's data is cached.

In facebook#27505, I changed the implementation so that it only "upgrades" the
priority of the transition for a single attempt. If the attempt
suspends, say because the data is not cached after all, from then on it
should be treated as a normal transition.

But it turns out facebook#27505 did not work as intended, because it relied on
marking the root with pending synchronous work (root.pendingLanes),
which was never cleared until the popstate update completed.

The test scenarios I wrote accidentally worked for a different reason
related to suspending the work loop, which I'm currently in the middle
of refactoring.
Comment on lines +590 to +596
function getLanesOfEqualOrHigherPriority(lanes: Lane | Lanes): Lanes {
// Create a mask with all bits to the right or same as the highest bit.
// So if lanes is 0b100, the result would be 0b111.
// If lanes is 0b101, the result would be 0b111.
const lowestPriorityLaneIndex = 31 - clz32(lanes);
return (1 << (lowestPriorityLaneIndex + 1)) - 1;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

That makes sense to me now 👍🏻

@acdlite acdlite merged commit ee7f675 into facebook:main Aug 23, 2024
184 checks passed
github-actions bot pushed a commit that referenced this pull request Aug 23, 2024
This is a refactor of the fix in #27505.

When a transition update is scheduled by a popstate event, (i.e. a back/
forward navigation) we attempt to render it synchronously even though
it's a transition, since it's likely the previous page's data is cached.

In #27505, I changed the implementation so that it only "upgrades" the
priority of the transition for a single attempt. If the attempt
suspends, say because the data is not cached after all, from then on it
should be treated as a normal transition.

But it turns out #27505 did not work as intended, because it relied on
marking the root with pending synchronous work (root.pendingLanes),
which was never cleared until the popstate update completed.

The test scenarios I wrote accidentally worked for a different reason
related to suspending the work loop, which I'm currently in the middle
of refactoring.

DiffTrain build for commit ee7f675.
github-actions bot pushed a commit that referenced this pull request Aug 23, 2024
This is a refactor of the fix in #27505.

When a transition update is scheduled by a popstate event, (i.e. a back/
forward navigation) we attempt to render it synchronously even though
it's a transition, since it's likely the previous page's data is cached.

In #27505, I changed the implementation so that it only "upgrades" the
priority of the transition for a single attempt. If the attempt
suspends, say because the data is not cached after all, from then on it
should be treated as a normal transition.

But it turns out #27505 did not work as intended, because it relied on
marking the root with pending synchronous work (root.pendingLanes),
which was never cleared until the popstate update completed.

The test scenarios I wrote accidentally worked for a different reason
related to suspending the work loop, which I'm currently in the middle
of refactoring.

DiffTrain build for [ee7f675](ee7f675)
acdlite added a commit that referenced this pull request Sep 4, 2024
### Based on

- #30761 
- #30759 

---

`use` has an optimization where in some cases it can suspend the work
loop during the render phase until the data has resolved, rather than
unwind the stack and lose context. However, the current implementation
is not compatible with sibling prerendering. So I've temporarily
disabled it until the sibling prerendering has been refactored. We will
add it back in a later step.
github-actions bot pushed a commit that referenced this pull request Sep 4, 2024
### Based on

- #30761
- #30759

---

`use` has an optimization where in some cases it can suspend the work
loop during the render phase until the data has resolved, rather than
unwind the stack and lose context. However, the current implementation
is not compatible with sibling prerendering. So I've temporarily
disabled it until the sibling prerendering has been refactored. We will
add it back in a later step.

DiffTrain build for [8b4c54c](8b4c54c)
github-actions bot pushed a commit that referenced this pull request Sep 4, 2024
### Based on

- #30761
- #30759

---

`use` has an optimization where in some cases it can suspend the work
loop during the render phase until the data has resolved, rather than
unwind the stack and lose context. However, the current implementation
is not compatible with sibling prerendering. So I've temporarily
disabled it until the sibling prerendering has been refactored. We will
add it back in a later step.

DiffTrain build for commit 8b4c54c.
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