diff --git a/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js b/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js index e6f8c3277d3a2..919fbb059f76b 100644 --- a/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js +++ b/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js @@ -2734,6 +2734,62 @@ describe('InspectedElement', () => { }); }); + it('inspecting nested renderers should not throw', async () => { + // Ignoring react art warnings + spyOn(console, 'error'); + const ReactArt = require('react-art'); + const ArtSVGMode = require('art/modes/svg'); + const ARTCurrentMode = require('art/modes/current'); + store.componentFilters = []; + + ARTCurrentMode.setCurrent(ArtSVGMode); + const {Surface, Group} = ReactArt; + + function Child() { + return ( + + + + ); + } + function App() { + return ; + } + + await utils.actAsync(() => { + legacyRender(, document.createElement('div')); + }); + expect(store).toMatchInlineSnapshot(` + [root] + ▾ + ▾ + ▾ + + [root] + + `); + + const inspectedElement = await inspectElementAtIndex(4); + expect(inspectedElement.owners).toMatchInlineSnapshot(` + Array [ + Object { + "displayName": "Child", + "hocDisplayNames": null, + "id": 3, + "key": null, + "type": 5, + }, + Object { + "displayName": "App", + "hocDisplayNames": null, + "id": 2, + "key": null, + "type": 5, + }, + ] + `); + }); + describe('error boundary', () => { it('can toggle error', async () => { class LocalErrorBoundary extends React.Component { diff --git a/packages/react-devtools-shared/src/backend/renderer.js b/packages/react-devtools-shared/src/backend/renderer.js index 32ce8e2a9fe55..4b67a7a8ebe9c 100644 --- a/packages/react-devtools-shared/src/backend/renderer.js +++ b/packages/react-devtools-shared/src/backend/renderer.js @@ -548,6 +548,17 @@ export function getInternalReactConstants( }; } +// Map of one or more Fibers in a pair to their unique id number. +// We track both Fibers to support Fast Refresh, +// which may forcefully replace one of the pair as part of hot reloading. +// In that case it's still important to be able to locate the previous ID during subsequent renders. +const fiberToIDMap: Map = new Map(); + +// Map of id to one (arbitrary) Fiber in a pair. +// This Map is used to e.g. get the display name for a Fiber or schedule an update, +// operations that should be the same whether the current and work-in-progress Fiber is used. +const idToArbitraryFiberMap: Map = new Map(); + export function attach( hook: DevToolsHook, rendererID: number, @@ -1085,17 +1096,6 @@ export function attach( } } - // Map of one or more Fibers in a pair to their unique id number. - // We track both Fibers to support Fast Refresh, - // which may forcefully replace one of the pair as part of hot reloading. - // In that case it's still important to be able to locate the previous ID during subsequent renders. - const fiberToIDMap: Map = new Map(); - - // Map of id to one (arbitrary) Fiber in a pair. - // This Map is used to e.g. get the display name for a Fiber or schedule an update, - // operations that should be the same whether the current and work-in-progress Fiber is used. - const idToArbitraryFiberMap: Map = new Map(); - // When profiling is supported, we store the latest tree base durations for each Fiber. // This is so that we can quickly capture a snapshot of those values if profiling starts. // If we didn't store these values, we'd have to crawl the tree when profiling started,