fix[devtools]: check if fiber is unmounted before trying to highlight (#26983)
For React Native environment, we sometimes spam the console with warnings `"Could not find Fiber with id ..."`. This is an attempt to fix this or at least reduce the amount of such potential warnings being thrown. Now checking if fiber is already unnmounted before trying to get native nodes for fiber. This might happen if you try to inspect an element in DevTools, but at the time when event has been received, the element was already unmounted.
Ruslan Lesiutin committed
Jun 22, 2023 at 08:51 UTC
794b770dbd6be48d42438ea76911d32c37c7dd6e
4 files changed
+26
-19
packages/react-devtools-shared/src/backend/legacy/renderer.js
+5
@@ -1101,6 +1101,10 @@ export function attach(
1101
1102
function unpatchConsoleForStrictMode() {}
1103
1104
+ function hasFiberWithId(id: number): boolean {
1105
+ return idToInternalInstanceMap.has(id);
1106
+ }
1107
+
1108
return {
1109
clearErrorsAndWarnings,
1110
clearErrorsForFiberID,
@@ -1124,6 +1128,7 @@ export function attach(
1128
handleCommitFiberRoot,
1129
handleCommitFiberUnmount,
1130
handlePostCommitFiberRoot,
1131
+ hasFiberWithId,
1132
inspectElement,
1133
logElementToConsole,
1134
overrideError,
packages/react-devtools-shared/src/backend/renderer.js
+9
-14
@@ -2736,21 +2736,11 @@ export function attach(
2736
2737
function findNativeNodesForFiberID(id: number) {
2738
try {
2739
- let fiber = findCurrentFiberUsingSlowPathById(id);
2739
+ const fiber = findCurrentFiberUsingSlowPathById(id);
2740
if (fiber === null) {
2741
return null;
2742
}
2743
- // Special case for a timed-out Suspense.
2744
- const isTimedOutSuspense =
2745
- fiber.tag === SuspenseComponent && fiber.memoizedState !== null;
2746
- if (isTimedOutSuspense) {
2747
- // A timed-out Suspense's findDOMNode is useless.
2748
- // Try our best to find the fallback directly.
2749
- const maybeFallbackFiber = fiber.child && fiber.child.sibling;
2750
- if (maybeFallbackFiber != null) {
2751
- fiber = maybeFallbackFiber;
2752
- }
2753
- }
2743
+
2744
const hostFibers = findAllCurrentHostFibers(id);
2745
return hostFibers.map(hostFiber => hostFiber.stateNode).filter(Boolean);
2746
} catch (err) {
@@ -2759,9 +2749,9 @@ export function attach(
2749
}
2750
}
2751
2762
- function getDisplayNameForFiberID(id: number) {
2752
+ function getDisplayNameForFiberID(id: number): null | string {
2753
const fiber = idToArbitraryFiberMap.get(id);
2764
- return fiber != null ? getDisplayNameForFiber(((fiber: any): Fiber)) : null;
2754
+ return fiber != null ? getDisplayNameForFiber(fiber) : null;
2755
}
2756
2757
function getFiberForNative(hostInstance: NativeType) {
@@ -4456,6 +4446,10 @@ export function attach(
4446
traceUpdatesEnabled = isEnabled;
4447
}
4448
4449
+ function hasFiberWithId(id: number): boolean {
4450
+ return idToArbitraryFiberMap.has(id);
4451
+ }
4452
+
4453
return {
4454
cleanup,
4455
clearErrorsAndWarnings,
@@ -4476,6 +4470,7 @@ export function attach(
4470
handleCommitFiberRoot,
4471
handleCommitFiberUnmount,
4472
handlePostCommitFiberRoot,
4473
+ hasFiberWithId,
4474
inspectElement,
4475
logElementToConsole,
4476
patchConsoleForStrictMode,
packages/react-devtools-shared/src/backend/types.js
+1
@@ -379,6 +379,7 @@ export type RendererInterface = {
379
handleCommitFiberRoot: (fiber: Object, commitPriority?: number) => void,
380
handleCommitFiberUnmount: (fiber: Object) => void,
381
handlePostCommitFiberRoot: (fiber: Object) => void,
382
+ hasFiberWithId: (id: number) => boolean,
383
inspectElement: (
384
requestID: number,
385
id: number,
packages/react-devtools-shared/src/backend/views/Highlighter/index.js
+11
-5
@@ -104,15 +104,21 @@ export default function setupHighlighter(
104
const renderer = agent.rendererInterfaces[rendererID];
105
if (renderer == null) {
106
console.warn(`Invalid renderer id "${rendererID}" for element "${id}"`);
107
+
108
+ hideOverlay(agent);
109
+ return;
110
}
111
109
- let nodes: ?Array<HTMLElement> = null;
110
- if (renderer != null) {
111
- nodes = ((renderer.findNativeNodesForFiberID(
112
- id,
113
- ): any): ?Array<HTMLElement>);
112
+ // In some cases fiber may already be unmounted
113
+ if (!renderer.hasFiberWithId(id)) {
114
+ hideOverlay(agent);
115
+ return;
116
}
117
118
+ const nodes: ?Array<HTMLElement> = (renderer.findNativeNodesForFiberID(
119
+ id,
120
+ ): any);
121
+
122
if (nodes != null && nodes[0] != null) {
123
const node = nodes[0];
124
// $FlowFixMe[method-unbinding]