Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Native: Export getInspectorDataForInstance API #21572

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/react-native-renderer/src/ReactFabric.js
Expand Up @@ -23,6 +23,7 @@ import {
injectIntoDevTools,
getPublicRootInstance,
} from 'react-reconciler/src/ReactFiberReconciler';
import {getInspectorDataForInstance} from './ReactNativeFiberInspector';

import {createPortal as createPortalImpl} from 'react-reconciler/src/ReactPortal';
import {setBatchingImplementation} from './legacy-events/ReactGenericBatching';
Expand Down Expand Up @@ -260,6 +261,9 @@ export {
unmountComponentAtNode,
stopSurface,
createPortal,
// This export is typically undefined in production builds.
// See the "enableGetInspectorDataForInstanceInProduction" flag.
getInspectorDataForInstance,
};

injectIntoDevTools({
Expand Down
126 changes: 71 additions & 55 deletions packages/react-native-renderer/src/ReactNativeFiberInspector.js
Expand Up @@ -19,67 +19,24 @@ import {HostComponent} from 'react-reconciler/src/ReactWorkTags';
import invariant from 'shared/invariant';
// Module provided by RN:
import {UIManager} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';

import {enableGetInspectorDataForInstanceInProduction} from 'shared/ReactFeatureFlags';
import {getClosestInstanceFromNode} from './ReactNativeComponentTree';

const emptyObject = {};
if (__DEV__) {
Object.freeze(emptyObject);
}

let getInspectorDataForViewTag;
let getInspectorDataForViewAtPoint;

if (__DEV__) {
const traverseOwnerTreeUp = function(hierarchy, instance: any) {
if (instance) {
hierarchy.unshift(instance);
traverseOwnerTreeUp(hierarchy, instance._debugOwner);
}
};

const getOwnerHierarchy = function(instance: any) {
const hierarchy = [];
traverseOwnerTreeUp(hierarchy, instance);
return hierarchy;
};

const lastNonHostInstance = function(hierarchy) {
for (let i = hierarchy.length - 1; i > 1; i--) {
const instance = hierarchy[i];

if (instance.tag !== HostComponent) {
return instance;
}
}
return hierarchy[0];
};

const getHostProps = function(fiber) {
const host = findCurrentHostFiber(fiber);
if (host) {
return host.memoizedProps || emptyObject;
}
return emptyObject;
};

const getHostNode = function(fiber: Fiber | null, findNodeHandle) {
let hostNode;
// look for children first for the hostNode
// as composite fibers do not have a hostNode
while (fiber) {
if (fiber.stateNode !== null && fiber.tag === HostComponent) {
hostNode = findNodeHandle(fiber.stateNode);
}
if (hostNode) {
return hostNode;
}
fiber = fiber.child;
}
return null;
};
let createHierarchy;
let getHostNode;
let getHostProps;
let lastNonHostInstance;
let getInspectorDataForInstance;
let getOwnerHierarchy;
let traverseOwnerTreeUp;

const createHierarchy = function(fiberHierarchy) {
if (__DEV__ || enableGetInspectorDataForInstanceInProduction) {
createHierarchy = function(fiberHierarchy) {
return fiberHierarchy.map(fiber => ({
name: getComponentNameFromType(fiber.type),
getInspectorData: findNodeHandle => {
Expand Down Expand Up @@ -108,7 +65,33 @@ if (__DEV__) {
}));
};

const getInspectorDataForInstance = function(closestInstance): InspectorData {
getHostNode = function(fiber: Fiber | null, findNodeHandle) {
let hostNode;
// look for children first for the hostNode
// as composite fibers do not have a hostNode
while (fiber) {
if (fiber.stateNode !== null && fiber.tag === HostComponent) {
hostNode = findNodeHandle(fiber.stateNode);
}
if (hostNode) {
return hostNode;
}
fiber = fiber.child;
}
return null;
};

getHostProps = function(fiber) {
const host = findCurrentHostFiber(fiber);
if (host) {
return host.memoizedProps || emptyObject;
}
return emptyObject;
};

getInspectorDataForInstance = function(
closestInstance: Fiber | null,
): InspectorData {
// Handle case where user clicks outside of ReactNative
if (!closestInstance) {
return {
Expand All @@ -135,6 +118,35 @@ if (__DEV__) {
};
};

getOwnerHierarchy = function(instance: any) {
const hierarchy = [];
traverseOwnerTreeUp(hierarchy, instance);
return hierarchy;
};

lastNonHostInstance = function(hierarchy) {
for (let i = hierarchy.length - 1; i > 1; i--) {
const instance = hierarchy[i];

if (instance.tag !== HostComponent) {
return instance;
}
}
return hierarchy[0];
};

traverseOwnerTreeUp = function(hierarchy, instance: any) {
if (instance) {
hierarchy.unshift(instance);
traverseOwnerTreeUp(hierarchy, instance._debugOwner);
}
};
}

let getInspectorDataForViewTag;
let getInspectorDataForViewAtPoint;

if (__DEV__) {
getInspectorDataForViewTag = function(viewTag: number): Object {
const closestInstance = getClosestInstanceFromNode(viewTag);

Expand Down Expand Up @@ -258,4 +270,8 @@ if (__DEV__) {
};
}

export {getInspectorDataForViewAtPoint, getInspectorDataForViewTag};
export {
getInspectorDataForInstance,
getInspectorDataForViewAtPoint,
getInspectorDataForViewTag,
};
4 changes: 4 additions & 0 deletions packages/react-native-renderer/src/ReactNativeRenderer.js
Expand Up @@ -36,6 +36,7 @@ import {
UIManager,
legacySendAccessibilityEvent,
} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
import {getInspectorDataForInstance} from './ReactNativeFiberInspector';

import {getClosestInstanceFromNode} from './ReactNativeComponentTree';
import {
Expand Down Expand Up @@ -264,6 +265,9 @@ export {
createPortal,
batchedUpdates as unstable_batchedUpdates,
Internals as __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
// This export is typically undefined in production builds.
// See the "enableGetInspectorDataForInstanceInProduction" flag.
getInspectorDataForInstance,
};

injectIntoDevTools({
Expand Down
3 changes: 3 additions & 0 deletions packages/shared/ReactFeatureFlags.js
Expand Up @@ -105,6 +105,9 @@ export const enableNewReconciler = false;

export const disableNativeComponentFrames = false;

// Internal only.
export const enableGetInspectorDataForInstanceInProduction = false;

// Errors that are thrown while unmounting (or after in the case of passive effects)
// should bypass any error boundaries that are also unmounting (or have unmounted)
// and be handled by the nearest still-mounted boundary.
Expand Down
2 changes: 1 addition & 1 deletion packages/shared/forks/ReactFeatureFlags.native-fb.js
Expand Up @@ -47,7 +47,7 @@ export const disableNativeComponentFrames = false;
export const skipUnmountedBoundaries = false;
export const deletedTreeCleanUpLevel = 3;
export const enableSuspenseLayoutEffectSemantics = false;

export const enableGetInspectorDataForInstanceInProduction = true;
export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = false;

Expand Down
2 changes: 1 addition & 1 deletion packages/shared/forks/ReactFeatureFlags.native-oss.js
Expand Up @@ -46,7 +46,7 @@ export const disableNativeComponentFrames = false;
export const skipUnmountedBoundaries = false;
export const deletedTreeCleanUpLevel = 3;
export const enableSuspenseLayoutEffectSemantics = false;

export const enableGetInspectorDataForInstanceInProduction = false;
export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = false;

Expand Down
2 changes: 1 addition & 1 deletion packages/shared/forks/ReactFeatureFlags.test-renderer.js
Expand Up @@ -46,7 +46,7 @@ export const disableNativeComponentFrames = false;
export const skipUnmountedBoundaries = false;
export const deletedTreeCleanUpLevel = 3;
export const enableSuspenseLayoutEffectSemantics = false;

export const enableGetInspectorDataForInstanceInProduction = false;
export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = false;

Expand Down
Expand Up @@ -46,7 +46,7 @@ export const disableNativeComponentFrames = false;
export const skipUnmountedBoundaries = false;
export const deletedTreeCleanUpLevel = 3;
export const enableSuspenseLayoutEffectSemantics = false;

export const enableGetInspectorDataForInstanceInProduction = false;
export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = false;

Expand Down
Expand Up @@ -46,7 +46,7 @@ export const disableNativeComponentFrames = false;
export const skipUnmountedBoundaries = false;
export const deletedTreeCleanUpLevel = 3;
export const enableSuspenseLayoutEffectSemantics = false;

export const enableGetInspectorDataForInstanceInProduction = false;
export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = false;

Expand Down
2 changes: 1 addition & 1 deletion packages/shared/forks/ReactFeatureFlags.testing.js
Expand Up @@ -46,7 +46,7 @@ export const disableNativeComponentFrames = false;
export const skipUnmountedBoundaries = false;
export const deletedTreeCleanUpLevel = 3;
export const enableSuspenseLayoutEffectSemantics = false;

export const enableGetInspectorDataForInstanceInProduction = false;
export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = false;

Expand Down
2 changes: 1 addition & 1 deletion packages/shared/forks/ReactFeatureFlags.testing.www.js
Expand Up @@ -46,7 +46,7 @@ export const disableNativeComponentFrames = false;
export const skipUnmountedBoundaries = true;
export const deletedTreeCleanUpLevel = 3;
export const enableSuspenseLayoutEffectSemantics = false;

export const enableGetInspectorDataForInstanceInProduction = false;
export const enableNewReconciler = false;
export const deferRenderPhaseUpdateToNextBatch = false;

Expand Down
2 changes: 1 addition & 1 deletion packages/shared/forks/ReactFeatureFlags.www.js
Expand Up @@ -60,7 +60,7 @@ export const warnAboutDeprecatedLifecycles = true;
export const disableLegacyContext = __EXPERIMENTAL__;
export const warnAboutStringRefs = false;
export const warnAboutDefaultPropsOnFunctionComponents = false;

export const enableGetInspectorDataForInstanceInProduction = false;
export const enableSuspenseServerRenderer = true;
export const enableSelectiveHydration = true;

Expand Down