Skip to content

Commit 56de3e4

Browse files
committed
Brute force error/warning count to update if it happens in passive effects
If a log is added in a passive effect it is too late for us to have picked it up in the tree traversal so it won't show up until that component is rerendered again. To avoid needing a map to look up the instance id, we do a brute force search over the whole tree to find any changes if this happens.
1 parent 006e1d7 commit 56de3e4

File tree

2 files changed

+48
-25
lines changed

2 files changed

+48
-25
lines changed

packages/react-devtools-shared/src/__tests__/store-test.js

+4-24
Original file line numberDiff line numberDiff line change
@@ -1817,13 +1817,8 @@ describe('Store', () => {
18171817
jest.runOnlyPendingTimers();
18181818
}
18191819

1820-
// Gross abstraction around pending passive warning/error delay.
1821-
function flushPendingPassiveErrorAndWarningCounts() {
1822-
jest.advanceTimersByTime(1000);
1823-
}
1824-
18251820
// @reactVersion >= 18.0
1826-
it('are counted (after a delay)', () => {
1821+
it('are counted (after no delay)', () => {
18271822
function Example() {
18281823
React.useEffect(() => {
18291824
console.error('test-only: passive error');
@@ -1838,13 +1833,6 @@ describe('Store', () => {
18381833
}, false);
18391834
});
18401835
flushPendingBridgeOperations();
1841-
expect(store).toMatchInlineSnapshot(`
1842-
[root]
1843-
<Example>
1844-
`);
1845-
1846-
// After a delay, passive effects should be committed as well
1847-
act(flushPendingPassiveErrorAndWarningCounts, false);
18481836
expect(store).toMatchInlineSnapshot(`
18491837
✕ 1, ⚠ 1
18501838
[root]
@@ -1879,8 +1867,9 @@ describe('Store', () => {
18791867
}, false);
18801868
flushPendingBridgeOperations();
18811869
expect(store).toMatchInlineSnapshot(`
1870+
✕ 1, ⚠ 1
18821871
[root]
1883-
<Example>
1872+
<Example> ✕⚠
18841873
`);
18851874

18861875
// Before warnings and errors have flushed, flush another commit.
@@ -1894,22 +1883,13 @@ describe('Store', () => {
18941883
}, false);
18951884
flushPendingBridgeOperations();
18961885
expect(store).toMatchInlineSnapshot(`
1897-
1, ⚠ 1
1886+
2, ⚠ 2
18981887
[root]
18991888
<Example> ✕⚠
19001889
<Noop>
19011890
`);
19021891
});
19031892

1904-
// After a delay, passive effects should be committed as well
1905-
act(flushPendingPassiveErrorAndWarningCounts, false);
1906-
expect(store).toMatchInlineSnapshot(`
1907-
✕ 2, ⚠ 2
1908-
[root]
1909-
<Example> ✕⚠
1910-
<Noop>
1911-
`);
1912-
19131893
act(() => unmount());
19141894
expect(store).toMatchInlineSnapshot(``);
19151895
});

packages/react-devtools-shared/src/backend/fiber/renderer.js

+44-1
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,32 @@ export function attach(
970970
// lets the Fiber get reparented/remounted and still observe the previous errors/warnings.
971971
// Unless we explicitly clear the logs from a Fiber.
972972
const fiberToComponentLogsMap: WeakMap<Fiber, ComponentLogs> = new WeakMap();
973+
// Tracks whether we've performed a commit since the last log. This is used to know
974+
// whether we received any new logs between the commit and post commit phases. I.e.
975+
// if any passive effects called console.warn / console.error.
976+
let needsToFlushComponentLogs = false;
977+
978+
function bruteForceFlushErrorsAndWarnings() {
979+
// Refresh error/warning count for all mounted unfiltered Fibers.
980+
let hasChanges = false;
981+
// eslint-disable-next-line no-for-of-loops/no-for-of-loops
982+
for (const devtoolsInstance of idToDevToolsInstanceMap.values()) {
983+
if (devtoolsInstance.kind === FIBER_INSTANCE) {
984+
const fiber = devtoolsInstance.data;
985+
const componentLogsEntry = fiberToComponentLogsMap.get(fiber);
986+
const changed = recordConsoleLogs(devtoolsInstance, componentLogsEntry);
987+
if (changed) {
988+
hasChanges = true;
989+
updateMostRecentlyInspectedElementIfNecessary(devtoolsInstance.id);
990+
}
991+
} else {
992+
// Virtual Instances cannot log in passive effects and so never appear here.
993+
}
994+
}
995+
if (hasChanges) {
996+
flushPendingEvents();
997+
}
998+
}
973999

9741000
function clearErrorsAndWarnings() {
9751001
// Note, this only clears logs for Fibers that have instances. If they're filtered
@@ -1101,10 +1127,12 @@ export function attach(
11011127
}
11021128

11031129
// The changes will be flushed later when we commit.
1104-
// TODO: If the log happened in a passive effect, then this happens after we've
1130+
1131+
// If the log happened in a passive effect, then this happens after we've
11051132
// already committed the new tree so the change won't show up until we rerender
11061133
// that component again. We need to visit a Component with passive effects in
11071134
// handlePostCommitFiberRoot again to ensure that we flush the changes after passive.
1135+
needsToFlushComponentLogs = true;
11081136
}
11091137

11101138
// Patching the console enables DevTools to do a few useful things:
@@ -1322,6 +1350,8 @@ export function attach(
13221350
});
13231351

13241352
flushPendingEvents();
1353+
1354+
needsToFlushComponentLogs = false;
13251355
}
13261356

13271357
function getEnvironmentNames(): Array<string> {
@@ -3464,6 +3494,8 @@ export function attach(
34643494
mountFiberRecursively(root.current, false);
34653495

34663496
flushPendingEvents(root);
3497+
3498+
needsToFlushComponentLogs = false;
34673499
currentRoot = (null: any);
34683500
});
34693501
}
@@ -3486,6 +3518,15 @@ export function attach(
34863518
passiveEffectDuration;
34873519
}
34883520
}
3521+
3522+
if (needsToFlushComponentLogs) {
3523+
// We received new logs after commit. I.e. in a passive effect. We need to
3524+
// traverse the tree to find the affected ones. If we just moved the whole
3525+
// tree traversal from handleCommitFiberRoot to handlePostCommitFiberRoot
3526+
// this wouldn't be needed. For now we just brute force check all instances.
3527+
// This is not that common of a case.
3528+
bruteForceFlushErrorsAndWarnings();
3529+
}
34893530
}
34903531

34913532
function handleCommitFiberRoot(
@@ -3595,6 +3636,8 @@ export function attach(
35953636
// We're done here.
35963637
flushPendingEvents(root);
35973638

3639+
needsToFlushComponentLogs = false;
3640+
35983641
if (traceUpdatesEnabled) {
35993642
hook.emit('traceUpdates', traceUpdatesForNodes);
36003643
}

0 commit comments

Comments
 (0)