@samitouri / QOS-React-2 / commits / 4758e4533e

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).

Brian Vaughn committed Jul 26, 2021 at 09:56 UTC 4758e4533e933d29b1c3a960794eef354800f786
12 files changed +90 -63
packages/react-native-renderer/src/ReactFabric.js
+4
@@ -23,6 +23,7 @@ import {
23 injectIntoDevTools,
24 getPublicRootInstance,
25 } from 'react-reconciler/src/ReactFiberReconciler';
26 +import {getInspectorDataForInstance} from './ReactNativeFiberInspector';
27
28 import {createPortal as createPortalImpl} from 'react-reconciler/src/ReactPortal';
29 import {setBatchingImplementation} from './legacy-events/ReactGenericBatching';
@@ -260,6 +261,9 @@ export {
261 unmountComponentAtNode,
262 stopSurface,
263 createPortal,
264 + // This export is typically undefined in production builds.
265 + // See the "enableGetInspectorDataForInstanceInProduction" flag.
266 + getInspectorDataForInstance,
267 };
268
269 injectIntoDevTools({
packages/react-native-renderer/src/ReactNativeFiberInspector.js
+71 -55
@@ -19,7 +19,7 @@ import {HostComponent} from 'react-reconciler/src/ReactWorkTags';
19 import invariant from 'shared/invariant';
20 // Module provided by RN:
21 import {UIManager} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
22 -
22 +import {enableGetInspectorDataForInstanceInProduction} from 'shared/ReactFeatureFlags';
23 import {getClosestInstanceFromNode} from './ReactNativeComponentTree';
24
25 const emptyObject = {};
@@ -27,59 +27,16 @@ if (__DEV__) {
27 Object.freeze(emptyObject);
28 }
29
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;
37
82 - const createHierarchy = function(fiberHierarchy) {
38 +if (__DEV__ || enableGetInspectorDataForInstanceInProduction) {
39 + createHierarchy = function(fiberHierarchy) {
40 return fiberHierarchy.map(fiber => ({
41 name: getComponentNameFromType(fiber.type),
42 getInspectorData: findNodeHandle => {
@@ -108,7 +65,33 @@ if (__DEV__) {
65 }));
66 };
67
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 {
95 // Handle case where user clicks outside of ReactNative
96 if (!closestInstance) {
97 return {
@@ -135,6 +118,35 @@ if (__DEV__) {
118 };
119 };
120
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__) {
150 getInspectorDataForViewTag = function(viewTag: number): Object {
151 const closestInstance = getClosestInstanceFromNode(viewTag);
152
@@ -258,4 +270,8 @@ if (__DEV__) {
270 };
271 }
272
261 -export {getInspectorDataForViewAtPoint, getInspectorDataForViewTag};
273 +export {
274 + getInspectorDataForInstance,
275 + getInspectorDataForViewAtPoint,
276 + getInspectorDataForViewTag,
277 +};
packages/react-native-renderer/src/ReactNativeRenderer.js
+4
@@ -36,6 +36,7 @@ import {
36 UIManager,
37 legacySendAccessibilityEvent,
38 } from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
39 +import {getInspectorDataForInstance} from './ReactNativeFiberInspector';
40
41 import {getClosestInstanceFromNode} from './ReactNativeComponentTree';
42 import {
@@ -264,6 +265,9 @@ export {
265 createPortal,
266 batchedUpdates as unstable_batchedUpdates,
267 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,
271 };
272
273 injectIntoDevTools({
packages/shared/ReactFeatureFlags.js
+3
@@ -105,6 +105,9 @@ export const enableNewReconciler = false;
105
106 export const disableNativeComponentFrames = false;
107
108 +// Internal only.
109 +export const enableGetInspectorDataForInstanceInProduction = false;
110 +
111 // Errors that are thrown while unmounting (or after in the case of passive effects)
112 // should bypass any error boundaries that are also unmounting (or have unmounted)
113 // and be handled by the nearest still-mounted boundary.
packages/shared/forks/ReactFeatureFlags.native-fb.js
+1 -1
@@ -47,7 +47,7 @@ export const disableNativeComponentFrames = false;
47 export const skipUnmountedBoundaries = false;
48 export const deletedTreeCleanUpLevel = 3;
49 export const enableSuspenseLayoutEffectSemantics = false;
50 -
50 +export const enableGetInspectorDataForInstanceInProduction = true;
51 export const enableNewReconciler = false;
52 export const deferRenderPhaseUpdateToNextBatch = false;
53
packages/shared/forks/ReactFeatureFlags.native-oss.js
+1 -1
@@ -46,7 +46,7 @@ export const disableNativeComponentFrames = false;
46 export const skipUnmountedBoundaries = false;
47 export const deletedTreeCleanUpLevel = 3;
48 export const enableSuspenseLayoutEffectSemantics = false;
49 -
49 +export const enableGetInspectorDataForInstanceInProduction = false;
50 export const enableNewReconciler = false;
51 export const deferRenderPhaseUpdateToNextBatch = false;
52
packages/shared/forks/ReactFeatureFlags.test-renderer.js
+1 -1
@@ -46,7 +46,7 @@ export const disableNativeComponentFrames = false;
46 export const skipUnmountedBoundaries = false;
47 export const deletedTreeCleanUpLevel = 3;
48 export const enableSuspenseLayoutEffectSemantics = false;
49 -
49 +export const enableGetInspectorDataForInstanceInProduction = false;
50 export const enableNewReconciler = false;
51 export const deferRenderPhaseUpdateToNextBatch = false;
52
packages/shared/forks/ReactFeatureFlags.test-renderer.native.js
+1 -1
@@ -46,7 +46,7 @@ export const disableNativeComponentFrames = false;
46 export const skipUnmountedBoundaries = false;
47 export const deletedTreeCleanUpLevel = 3;
48 export const enableSuspenseLayoutEffectSemantics = false;
49 -
49 +export const enableGetInspectorDataForInstanceInProduction = false;
50 export const enableNewReconciler = false;
51 export const deferRenderPhaseUpdateToNextBatch = false;
52
packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
+1 -1
@@ -46,7 +46,7 @@ export const disableNativeComponentFrames = false;
46 export const skipUnmountedBoundaries = false;
47 export const deletedTreeCleanUpLevel = 3;
48 export const enableSuspenseLayoutEffectSemantics = false;
49 -
49 +export const enableGetInspectorDataForInstanceInProduction = false;
50 export const enableNewReconciler = false;
51 export const deferRenderPhaseUpdateToNextBatch = false;
52
packages/shared/forks/ReactFeatureFlags.testing.js
+1 -1
@@ -46,7 +46,7 @@ export const disableNativeComponentFrames = false;
46 export const skipUnmountedBoundaries = false;
47 export const deletedTreeCleanUpLevel = 3;
48 export const enableSuspenseLayoutEffectSemantics = false;
49 -
49 +export const enableGetInspectorDataForInstanceInProduction = false;
50 export const enableNewReconciler = false;
51 export const deferRenderPhaseUpdateToNextBatch = false;
52
packages/shared/forks/ReactFeatureFlags.testing.www.js
+1 -1
@@ -46,7 +46,7 @@ export const disableNativeComponentFrames = false;
46 export const skipUnmountedBoundaries = true;
47 export const deletedTreeCleanUpLevel = 3;
48 export const enableSuspenseLayoutEffectSemantics = false;
49 -
49 +export const enableGetInspectorDataForInstanceInProduction = false;
50 export const enableNewReconciler = false;
51 export const deferRenderPhaseUpdateToNextBatch = false;
52
packages/shared/forks/ReactFeatureFlags.www.js
+1 -1
@@ -60,7 +60,7 @@ export const warnAboutDeprecatedLifecycles = true;
60 export const disableLegacyContext = __EXPERIMENTAL__;
61 export const warnAboutStringRefs = false;
62 export const warnAboutDefaultPropsOnFunctionComponents = false;
63 -
63 +export const enableGetInspectorDataForInstanceInProduction = false;
64 export const enableSuspenseServerRenderer = true;
65 export const enableSelectiveHydration = true;
66