mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Adds a ReactNativeInspector API to ReactNativeRenderer (#9691)
* fixed conflicts with master * splits fiber and stack implementations * prettier run * updated fiber implementation based on feedback * updated fiber implementation for selecting inspector hierarchy * run of prettier * fixed flow issues * updated stack implementation * fixes an implementation difference where before it wasnt properly understoof * addresses comments in PR feedback * updated stack inspector to use emptyObject * Update ReactNativeFiberInspector.js Fixes a flow error * fixes last flow error * prettier * applied changes to how viewConfig works for fibers and extracted measure out * fixed bad paste * fixes flow errors * prettyify * revmoed getComponentName changes * updated logic for getHostProps and addressed other PR feedback * improved throwing to invariant and update stack implemenation based on feedback * prettier
This commit is contained in:
@@ -23,6 +23,7 @@ const ReactNativeInjection = require('ReactNativeInjection');
|
||||
const ReactNativeTagHandles = require('ReactNativeTagHandles');
|
||||
const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry');
|
||||
const ReactPortal = require('ReactPortal');
|
||||
const ReactNativeFiberInspector = require('ReactNativeFiberInspector');
|
||||
const ReactVersion = require('ReactVersion');
|
||||
const UIManager = require('UIManager');
|
||||
|
||||
@@ -465,6 +466,7 @@ if (typeof injectInternals === 'function') {
|
||||
injectInternals({
|
||||
findFiberByHostInstance: ReactNativeComponentTree.getClosestInstanceFromNode,
|
||||
findHostInstanceByFiber: NativeRenderer.findHostInstance,
|
||||
getInspectorDataForViewTag: ReactNativeFiberInspector.getInspectorDataForViewTag,
|
||||
// This is an enum because we may add more (e.g. profiler build)
|
||||
bundleType: __DEV__ ? 1 : 0,
|
||||
version: ReactVersion,
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactNativeFiberInspector
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const ReactNativeComponentTree = require('ReactNativeComponentTree');
|
||||
const ReactFiberTreeReflection = require('ReactFiberTreeReflection');
|
||||
const getComponentName = require('getComponentName');
|
||||
const emptyObject = require('fbjs/lib/emptyObject');
|
||||
const ReactTypeOfWork = require('ReactTypeOfWork');
|
||||
const UIManager = require('UIManager');
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
|
||||
const {getClosestInstanceFromNode} = ReactNativeComponentTree;
|
||||
const {findCurrentFiberUsingSlowPath} = ReactFiberTreeReflection;
|
||||
const {HostComponent} = ReactTypeOfWork;
|
||||
|
||||
import type {Fiber} from 'ReactFiber';
|
||||
|
||||
let getInspectorDataForViewTag;
|
||||
|
||||
if (__DEV__) {
|
||||
var traverseOwnerTreeUp = function(hierarchy, instance: any) {
|
||||
if (instance) {
|
||||
hierarchy.unshift(instance);
|
||||
traverseOwnerTreeUp(hierarchy, instance._debugOwner);
|
||||
}
|
||||
};
|
||||
|
||||
var getOwnerHierarchy = function(instance: any) {
|
||||
var hierarchy = [];
|
||||
traverseOwnerTreeUp(hierarchy, instance);
|
||||
return hierarchy;
|
||||
};
|
||||
|
||||
var 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];
|
||||
};
|
||||
|
||||
var getHostProps = function(fiber) {
|
||||
const host = ReactFiberTreeReflection.findCurrentHostFiber(fiber);
|
||||
if (host) {
|
||||
return host.memoizedProps || emptyObject;
|
||||
}
|
||||
return emptyObject;
|
||||
};
|
||||
|
||||
var 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;
|
||||
};
|
||||
|
||||
var stripTopSecret = str =>
|
||||
typeof str === 'string' && str.replace('topsecret-', '');
|
||||
|
||||
var createHierarchy = function(fiberHierarchy) {
|
||||
return fiberHierarchy.map(fiber => ({
|
||||
name: stripTopSecret(getComponentName(fiber)),
|
||||
getInspectorData: findNodeHandle => ({
|
||||
measure: callback =>
|
||||
UIManager.measure(getHostNode(fiber, findNodeHandle), callback),
|
||||
props: getHostProps(fiber),
|
||||
source: fiber._debugSource,
|
||||
}),
|
||||
}));
|
||||
};
|
||||
|
||||
getInspectorDataForViewTag = function(viewTag: number): Object {
|
||||
const fiber = findCurrentFiberUsingSlowPath(
|
||||
getClosestInstanceFromNode(viewTag),
|
||||
);
|
||||
const fiberHierarchy = getOwnerHierarchy(fiber);
|
||||
const instance = lastNonHostInstance(fiberHierarchy);
|
||||
const hierarchy = createHierarchy(fiberHierarchy);
|
||||
const props = getHostProps(instance);
|
||||
const source = instance._debugSource;
|
||||
const selection = fiberHierarchy.indexOf(instance);
|
||||
|
||||
return {
|
||||
hierarchy,
|
||||
instance,
|
||||
props,
|
||||
selection,
|
||||
source,
|
||||
};
|
||||
};
|
||||
} else {
|
||||
getInspectorDataForViewTag = () => {
|
||||
invariant(
|
||||
false,
|
||||
'getInspectorDataForViewTag() is not available in production',
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getInspectorDataForViewTag,
|
||||
};
|
||||
@@ -16,6 +16,7 @@ var ReactNativeInjection = require('ReactNativeInjection');
|
||||
var ReactNativeMount = require('ReactNativeMount');
|
||||
var ReactNativeStackInjection = require('ReactNativeStackInjection');
|
||||
var ReactUpdates = require('ReactUpdates');
|
||||
var ReactNativeStackInspector = require('ReactNativeStackInspector');
|
||||
|
||||
var findNodeHandle = require('findNodeHandle');
|
||||
|
||||
@@ -81,6 +82,7 @@ if (
|
||||
},
|
||||
Mount: ReactNativeMount,
|
||||
Reconciler: require('ReactReconciler'),
|
||||
getInspectorDataForViewTag: ReactNativeStackInspector.getInspectorDataForViewTag,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactNativeStackInspector
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const ReactNativeComponentTree = require('ReactNativeComponentTree');
|
||||
const getComponentName = require('getComponentName');
|
||||
const emptyObject = require('fbjs/lib/emptyObject');
|
||||
const UIManager = require('UIManager');
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
|
||||
let getInspectorDataForViewTag;
|
||||
|
||||
if (__DEV__) {
|
||||
var traverseOwnerTreeUp = function(hierarchy, instance) {
|
||||
if (instance) {
|
||||
hierarchy.unshift(instance);
|
||||
traverseOwnerTreeUp(hierarchy, instance._currentElement._owner);
|
||||
}
|
||||
};
|
||||
|
||||
var getOwnerHierarchy = function(instance) {
|
||||
var hierarchy = [];
|
||||
traverseOwnerTreeUp(hierarchy, instance);
|
||||
return hierarchy;
|
||||
};
|
||||
|
||||
var lastNotNativeInstance = function(hierarchy) {
|
||||
for (let i = hierarchy.length - 1; i > 1; i--) {
|
||||
const instance = hierarchy[i];
|
||||
if (!instance.viewConfig) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
return hierarchy[0];
|
||||
};
|
||||
|
||||
var getHostProps = function(component) {
|
||||
const instance = component._instance;
|
||||
if (instance) {
|
||||
return instance.props || emptyObject;
|
||||
}
|
||||
return emptyObject;
|
||||
};
|
||||
|
||||
var createHierarchy = function(componentHierarchy) {
|
||||
return componentHierarchy.map(component => ({
|
||||
name: getComponentName(component),
|
||||
getInspectorData: () => ({
|
||||
measure: callback =>
|
||||
UIManager.measure(component.getHostNode(), callback),
|
||||
props: getHostProps(component),
|
||||
source: component._currentElement && component._currentElement._source,
|
||||
}),
|
||||
}));
|
||||
};
|
||||
|
||||
getInspectorDataForViewTag = function(viewTag: any): Object {
|
||||
const component = ReactNativeComponentTree.getClosestInstanceFromNode(
|
||||
viewTag,
|
||||
);
|
||||
const componentHierarchy = getOwnerHierarchy(component);
|
||||
const instance = lastNotNativeInstance(componentHierarchy);
|
||||
const hierarchy = createHierarchy(componentHierarchy);
|
||||
const props = getHostProps(instance);
|
||||
const source = instance._currentElement && instance._currentElement._source;
|
||||
const selection = componentHierarchy.indexOf(instance);
|
||||
|
||||
return {
|
||||
hierarchy,
|
||||
instance,
|
||||
props,
|
||||
selection,
|
||||
source,
|
||||
};
|
||||
};
|
||||
} else {
|
||||
getInspectorDataForViewTag = () => {
|
||||
invariant(
|
||||
false,
|
||||
'getInspectorDataForViewTag() is not available in production',
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getInspectorDataForViewTag,
|
||||
};
|
||||
Reference in New Issue
Block a user