-
Notifications
You must be signed in to change notification settings - Fork 47.3k
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
DevTools: Fix "unknown" updater in profiler when a component unsuspends #28330
base: main
Are you sure you want to change the base?
Conversation
Comparing: d77dd31...eb3f84b Critical size changesIncludes critical production bundles, as well as any change greater than 2%:
Significant size changesIncludes any change greater than 0.2%: Expand to show
|
@acdlite @kassens I was going to approve this test but noticed the assertions had to change with the modern root. Not really sure what this test is for but it looks like @kassens you omitted it from the original PR that converts to createRoot. Do either of you know if this needs to be maintained as a legacy mode test? |
We get the old diff --git a/packages/react-reconciler/src/__tests__/ReactUpdaters-test.internal.js b/packages/react-reconciler/src/__tests__/ReactUpdaters-test.internal.js
index d518159ce8..b45f7e6259 100644
--- a/packages/react-reconciler/src/__tests__/ReactUpdaters-test.internal.js
+++ b/packages/react-reconciler/src/__tests__/ReactUpdaters-test.internal.js
@@ -45,10 +45,19 @@ describe('updaters', () => {
}
const schedulerTags = [];
const schedulerTypes = [];
- fiberRoot.memoizedUpdaters.forEach(fiber => {
- schedulerTags.push(fiber.tag);
- schedulerTypes.push(fiber.elementType);
- });
+ if (fiberRoot.memoizedUpdaters.size > 0) {
+ fiberRoot.memoizedUpdaters.forEach(fiber => {
+ schedulerTags.push(fiber.tag);
+ schedulerTypes.push(fiber.elementType);
+ });
+ } else {
+ fiberRoot.pendingUpdatersLaneMap.forEach(pendingUpdaters => {
+ pendingUpdaters.forEach(fiber => {
+ schedulerTags.push(fiber.tag);
+ schedulerTypes.push(fiber.elementType);
+ });
+ });
+ }
allSchedulerTags.push(schedulerTags);
allSchedulerTypes.push(schedulerTypes);
}), I'm just now piecing |
ae87aca
to
16ee439
Compare
packages/react-reconciler/src/__tests__/ReactUpdaters-test.internal.js
Outdated
Show resolved
Hide resolved
16ee439
to
dcc5ca6
Compare
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
// TODO: When would we ever ping lanes that we aren't suspended on? | ||
root.pingedLanes |= pingedLanes; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to investigate this further? Just transferring the updaters from root.pingedLanes
to updateLane
isn't enough. For some reason we're pinging when root.suspendedLanes & pingedLanes === NoLanes
. Which seems odd intuitively but maybe the bug is root.suspendedLanes
having no overlap with pingedLanes
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When would we ever ping lanes that we aren't suspended on?
Maybe if we suspend on two Wakeables A and B, A gets pinged earlier, we unsuspend completely i.e. don't suspend on B again (e.g. conditional use
?) and then we wouldn't want to retry when B gets pinged?
Grasping for straws here since all tests still pass with this change.
@@ -266,9 +274,6 @@ describe('updaters', () => { | |||
await waitForAll([]); | |||
}); | |||
|
|||
// This test should be convertable to createRoot but the allScheduledTypes assertions are no longer the same | |||
// So I'm leaving it in legacy mode for now and just disabling if legacy mode is turned off | |||
// @gate !disableLegacyMode | |||
it('should cover suspense pings', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The original issue in the test was that the updater was on the Default lane, the updater got pinged, and then we said we should render on a Retry lane (markRootPinged
). This left the updater dangling in pending updaters since we only move the pending updaters to memoized on the lane we actually render (Retry lane).
// TODO: Is it ever ok to have dangling pending updaters or is this always a bug? | ||
// const lane = 1 << index; | ||
// throw new Error( | ||
// `Lane ${lane} has pending updaters. Either you didn't assert on all updates in your test or React is leaking updaters.`, | ||
// ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests that currently would fail this: https://app.circleci.com/pipelines/github/facebook/react/54155/workflows/17c8ec84-c64b-4fc1-bde6-6fcb7532513e/jobs/892710
@@ -625,6 +625,8 @@ export function markRootUpdated(root: FiberRoot, updateLane: Lane) { | |||
// idle updates until after all the regular updates have finished; there's no | |||
// way it could unblock a transition. | |||
if (updateLane !== IdleLane) { | |||
movePendingUpdatersToLane(root, root.pingedLanes, updateLane); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to transfer updaters from root.suspendedLanes
but I haven't really thought about this for more than a sec.
6a2add4
to
ffd8102
Compare
Fixes ```` SyntaxError: ~/react/packages/react-reconciler/src/ReactFiberLane.js: Compiling let/const in this block would add a closure (throwIfClosureRequired). 614 | if (updateLane !== IdleLane) { 615 | if (enableUpdaterTracking) { > 616 | if (isDevToolsPresent) { | ^ 617 | // transfer pending updaters from pingedLanes to updateLane 618 | const pendingUpdatersLaneMap = root.pendingUpdatersLaneMap; 619 | const updaters = pendingUpdatersLaneMap[laneToIndex(updateLane)]; ```
ffd8102
to
eb3f84b
Compare
Completes #28005
Closes #22603
When we pinged a Wakeable we marked the root as updated without moving the pending updaters from the pinged lanes to the update lane. This resulted in the update be marked as "unknown" in devtools. This may have also caused leaking of pending updaters since we cleared the pending lanes while keeping the updaters around on these lanes. Now we transfer all updaters from the
pendingLanes
to the designated update lane.Displaying the host root as the updater is still not as useful but that's another bug (see #29735).
Update: I think the actual bug is that we restore pending updaters on a ping instead of adding the source fiber to the pending updaters on the retry lane. Restoring pending updaters is essentially causing https://github.com/facebook/react/pull/29735/files#diff-4962849261d085a5fbf4389513ab1a3a9b442cc8e1c4629f130ba2e03ef2b6bfR382-R386. Not sure yet where to put that logic.
Test plan
Before:
After: