Skip to content

Commit 4758e45

Browse files
author
Brian Vaughn
authored
React Native: Export getInspectorDataForInstance API (#21572)
This PR exports a new top-level API, getInspectorDataForInstance, for React Native (both development and production). Although this change adds a new export to the DEV bundle, it only impacts the production bundle for internal builds (not what's published to NPM).
1 parent c76e4db commit 4758e45

12 files changed

+90
-63
lines changed

packages/react-native-renderer/src/ReactFabric.js

+4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
injectIntoDevTools,
2424
getPublicRootInstance,
2525
} from 'react-reconciler/src/ReactFiberReconciler';
26+
import {getInspectorDataForInstance} from './ReactNativeFiberInspector';
2627

2728
import {createPortal as createPortalImpl} from 'react-reconciler/src/ReactPortal';
2829
import {setBatchingImplementation} from './legacy-events/ReactGenericBatching';
@@ -260,6 +261,9 @@ export {
260261
unmountComponentAtNode,
261262
stopSurface,
262263
createPortal,
264+
// This export is typically undefined in production builds.
265+
// See the "enableGetInspectorDataForInstanceInProduction" flag.
266+
getInspectorDataForInstance,
263267
};
264268

265269
injectIntoDevTools({

packages/react-native-renderer/src/ReactNativeFiberInspector.js

+71-55
Original file line numberDiff line numberDiff line change
@@ -19,67 +19,24 @@ import {HostComponent} from 'react-reconciler/src/ReactWorkTags';
1919
import invariant from 'shared/invariant';
2020
// Module provided by RN:
2121
import {UIManager} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
22-
22+
import {enableGetInspectorDataForInstanceInProduction} from 'shared/ReactFeatureFlags';
2323
import {getClosestInstanceFromNode} from './ReactNativeComponentTree';
2424

2525
const emptyObject = {};
2626
if (__DEV__) {
2727
Object.freeze(emptyObject);
2828
}
2929

30-
let getInspectorDataForViewTag;
31-
let getInspectorDataForViewAtPoint;
32-
33-
if (__DEV__) {
34-
const traverseOwnerTreeUp = function(hierarchy, instance: any) {
35-
if (instance) {
36-
hierarchy.unshift(instance);
37-
traverseOwnerTreeUp(hierarchy, instance._debugOwner);
38-
}
39-
};
40-
41-
const getOwnerHierarchy = function(instance: any) {
42-
const hierarchy = [];
43-
traverseOwnerTreeUp(hierarchy, instance);
44-
return hierarchy;
45-
};
46-
47-
const lastNonHostInstance = function(hierarchy) {
48-
for (let i = hierarchy.length - 1; i > 1; i--) {
49-
const instance = hierarchy[i];
50-
51-
if (instance.tag !== HostComponent) {
52-
return instance;
53-
}
54-
}
55-
return hierarchy[0];
56-
};
57-
58-
const getHostProps = function(fiber) {
59-
const host = findCurrentHostFiber(fiber);
60-
if (host) {
61-
return host.memoizedProps || emptyObject;
62-
}
63-
return emptyObject;
64-
};
65-
66-
const getHostNode = function(fiber: Fiber | null, findNodeHandle) {
67-
let hostNode;
68-
// look for children first for the hostNode
69-
// as composite fibers do not have a hostNode
70-
while (fiber) {
71-
if (fiber.stateNode !== null && fiber.tag === HostComponent) {
72-
hostNode = findNodeHandle(fiber.stateNode);
73-
}
74-
if (hostNode) {
75-
return hostNode;
76-
}
77-
fiber = fiber.child;
78-
}
79-
return null;
80-
};
30+
let createHierarchy;
31+
let getHostNode;
32+
let getHostProps;
33+
let lastNonHostInstance;
34+
let getInspectorDataForInstance;
35+
let getOwnerHierarchy;
36+
let traverseOwnerTreeUp;
8137

82-
const createHierarchy = function(fiberHierarchy) {
38+
if (__DEV__ || enableGetInspectorDataForInstanceInProduction) {
39+
createHierarchy = function(fiberHierarchy) {
8340
return fiberHierarchy.map(fiber => ({
8441
name: getComponentNameFromType(fiber.type),
8542
getInspectorData: findNodeHandle => {
@@ -108,7 +65,33 @@ if (__DEV__) {
10865
}));
10966
};
11067

111-
const getInspectorDataForInstance = function(closestInstance): InspectorData {
68+
getHostNode = function(fiber: Fiber | null, findNodeHandle) {
69+
let hostNode;
70+
// look for children first for the hostNode
71+
// as composite fibers do not have a hostNode
72+
while (fiber) {
73+
if (fiber.stateNode !== null && fiber.tag === HostComponent) {
74+
hostNode = findNodeHandle(fiber.stateNode);
75+
}
76+
if (hostNode) {
77+
return hostNode;
78+
}
79+
fiber = fiber.child;
80+
}
81+
return null;
82+
};
83+
84+
getHostProps = function(fiber) {
85+
const host = findCurrentHostFiber(fiber);
86+
if (host) {
87+
return host.memoizedProps || emptyObject;
88+
}
89+
return emptyObject;
90+
};
91+
92+
getInspectorDataForInstance = function(
93+
closestInstance: Fiber | null,
94+
): InspectorData {
11295
// Handle case where user clicks outside of ReactNative
11396
if (!closestInstance) {
11497
return {
@@ -135,6 +118,35 @@ if (__DEV__) {
135118
};
136119
};
137120

121+
getOwnerHierarchy = function(instance: any) {
122+
const hierarchy = [];
123+
traverseOwnerTreeUp(hierarchy, instance);
124+
return hierarchy;
125+
};
126+
127+
lastNonHostInstance = function(hierarchy) {
128+
for (let i = hierarchy.length - 1; i > 1; i--) {
129+
const instance = hierarchy[i];
130+
131+
if (instance.tag !== HostComponent) {
132+
return instance;
133+
}
134+
}
135+
return hierarchy[0];
136+
};
137+
138+
traverseOwnerTreeUp = function(hierarchy, instance: any) {
139+
if (instance) {
140+
hierarchy.unshift(instance);
141+
traverseOwnerTreeUp(hierarchy, instance._debugOwner);
142+
}
143+
};
144+
}
145+
146+
let getInspectorDataForViewTag;
147+
let getInspectorDataForViewAtPoint;
148+
149+
if (__DEV__) {
138150
getInspectorDataForViewTag = function(viewTag: number): Object {
139151
const closestInstance = getClosestInstanceFromNode(viewTag);
140152

@@ -258,4 +270,8 @@ if (__DEV__) {
258270
};
259271
}
260272

261-
export {getInspectorDataForViewAtPoint, getInspectorDataForViewTag};
273+
export {
274+
getInspectorDataForInstance,
275+
getInspectorDataForViewAtPoint,
276+
getInspectorDataForViewTag,
277+
};

packages/react-native-renderer/src/ReactNativeRenderer.js

+4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {
3636
UIManager,
3737
legacySendAccessibilityEvent,
3838
} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
39+
import {getInspectorDataForInstance} from './ReactNativeFiberInspector';
3940

4041
import {getClosestInstanceFromNode} from './ReactNativeComponentTree';
4142
import {
@@ -264,6 +265,9 @@ export {
264265
createPortal,
265266
batchedUpdates as unstable_batchedUpdates,
266267
Internals as __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
268+
// This export is typically undefined in production builds.
269+
// See the "enableGetInspectorDataForInstanceInProduction" flag.
270+
getInspectorDataForInstance,
267271
};
268272

269273
injectIntoDevTools({

packages/shared/ReactFeatureFlags.js

+3
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ export const enableNewReconciler = false;
105105

106106
export const disableNativeComponentFrames = false;
107107

108+
// Internal only.
109+
export const enableGetInspectorDataForInstanceInProduction = false;
110+
108111
// Errors that are thrown while unmounting (or after in the case of passive effects)
109112
// should bypass any error boundaries that are also unmounting (or have unmounted)
110113
// and be handled by the nearest still-mounted boundary.

packages/shared/forks/ReactFeatureFlags.native-fb.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export const disableNativeComponentFrames = false;
4747
export const skipUnmountedBoundaries = false;
4848
export const deletedTreeCleanUpLevel = 3;
4949
export const enableSuspenseLayoutEffectSemantics = false;
50-
50+
export const enableGetInspectorDataForInstanceInProduction = true;
5151
export const enableNewReconciler = false;
5252
export const deferRenderPhaseUpdateToNextBatch = false;
5353

packages/shared/forks/ReactFeatureFlags.native-oss.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const disableNativeComponentFrames = false;
4646
export const skipUnmountedBoundaries = false;
4747
export const deletedTreeCleanUpLevel = 3;
4848
export const enableSuspenseLayoutEffectSemantics = false;
49-
49+
export const enableGetInspectorDataForInstanceInProduction = false;
5050
export const enableNewReconciler = false;
5151
export const deferRenderPhaseUpdateToNextBatch = false;
5252

packages/shared/forks/ReactFeatureFlags.test-renderer.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const disableNativeComponentFrames = false;
4646
export const skipUnmountedBoundaries = false;
4747
export const deletedTreeCleanUpLevel = 3;
4848
export const enableSuspenseLayoutEffectSemantics = false;
49-
49+
export const enableGetInspectorDataForInstanceInProduction = false;
5050
export const enableNewReconciler = false;
5151
export const deferRenderPhaseUpdateToNextBatch = false;
5252

packages/shared/forks/ReactFeatureFlags.test-renderer.native.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const disableNativeComponentFrames = false;
4646
export const skipUnmountedBoundaries = false;
4747
export const deletedTreeCleanUpLevel = 3;
4848
export const enableSuspenseLayoutEffectSemantics = false;
49-
49+
export const enableGetInspectorDataForInstanceInProduction = false;
5050
export const enableNewReconciler = false;
5151
export const deferRenderPhaseUpdateToNextBatch = false;
5252

packages/shared/forks/ReactFeatureFlags.test-renderer.www.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const disableNativeComponentFrames = false;
4646
export const skipUnmountedBoundaries = false;
4747
export const deletedTreeCleanUpLevel = 3;
4848
export const enableSuspenseLayoutEffectSemantics = false;
49-
49+
export const enableGetInspectorDataForInstanceInProduction = false;
5050
export const enableNewReconciler = false;
5151
export const deferRenderPhaseUpdateToNextBatch = false;
5252

packages/shared/forks/ReactFeatureFlags.testing.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const disableNativeComponentFrames = false;
4646
export const skipUnmountedBoundaries = false;
4747
export const deletedTreeCleanUpLevel = 3;
4848
export const enableSuspenseLayoutEffectSemantics = false;
49-
49+
export const enableGetInspectorDataForInstanceInProduction = false;
5050
export const enableNewReconciler = false;
5151
export const deferRenderPhaseUpdateToNextBatch = false;
5252

packages/shared/forks/ReactFeatureFlags.testing.www.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const disableNativeComponentFrames = false;
4646
export const skipUnmountedBoundaries = true;
4747
export const deletedTreeCleanUpLevel = 3;
4848
export const enableSuspenseLayoutEffectSemantics = false;
49-
49+
export const enableGetInspectorDataForInstanceInProduction = false;
5050
export const enableNewReconciler = false;
5151
export const deferRenderPhaseUpdateToNextBatch = false;
5252

packages/shared/forks/ReactFeatureFlags.www.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export const warnAboutDeprecatedLifecycles = true;
6060
export const disableLegacyContext = __EXPERIMENTAL__;
6161
export const warnAboutStringRefs = false;
6262
export const warnAboutDefaultPropsOnFunctionComponents = false;
63-
63+
export const enableGetInspectorDataForInstanceInProduction = false;
6464
export const enableSuspenseServerRenderer = true;
6565
export const enableSelectiveHydration = true;
6666

0 commit comments

Comments
 (0)