Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-render-hook

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-render-hook - npm Package Compare versions

Comparing version 1.0.1 to 1.1.0

lib/react-devtools/backend/traverseAllChildrenImpl.js

3

CHANGELOG.md

@@ -21,1 +21,4 @@ # Changelog

Update devDependencies
## v1.1.0
React 16.5.0 compatibility by updating devtools. Thanks @albertfdp for tracking this down!

6

lib/react-devtools/backend/attachRenderer.js

@@ -62,5 +62,7 @@ /**

extras.getReactElementFromNative = function (node) {
// $FlowFixMe
var id = renderer.Mount.getID(node);
while (node && node.parentNode && !id) {
node = node.parentNode;
// $FlowFixMe
id = renderer.Mount.getID(node);

@@ -117,3 +119,3 @@ }

hook.emit('unmount', { internalInstance: this, renderer: rid });
rootNodeIDMap.delete(this._rootNodeID, this);
rootNodeIDMap.delete(this._rootNodeID);
}

@@ -136,3 +138,3 @@ });

hook.emit('unmount', { internalInstance: internalInstance, renderer: rid });
rootNodeIDMap.delete(internalInstance._rootNodeID, internalInstance);
rootNodeIDMap.delete(internalInstance._rootNodeID);
}

@@ -139,0 +141,0 @@ });

@@ -13,14 +13,359 @@ /**

var getDataFiber = require('./getDataFiber');
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _require = require('./ReactTypeOfWork'),
ClassComponent = _require.ClassComponent,
HostRoot = _require.HostRoot;
var semver = require('semver');
// Inlined from ReactTypeOfSideEffect
var copyWithSet = require('./copyWithSet');
var getDisplayName = require('./getDisplayName');
function getInternalReactConstants(version) {
var ReactTypeOfWork;
var ReactSymbols;
var ReactTypeOfSideEffect;
var PerformedWork = 1;
// **********************************************************
// The section below is copy-pasted from files in React repo.
// Keep it in sync, and add version guards if it changes.
// **********************************************************
if (semver.gte(version, '16.4.3-alpha')) {
ReactTypeOfWork = {
FunctionalComponent: 0,
FunctionalComponentLazy: 1,
ClassComponent: 2,
ClassComponentLazy: 3,
IndeterminateComponent: 4,
HostRoot: 5,
HostPortal: 6,
HostComponent: 7,
HostText: 8,
Fragment: 9,
Mode: 10,
ContextConsumer: 11,
ContextProvider: 12,
ForwardRef: 13,
ForwardRefLazy: 14,
Profiler: 15,
PlaceholderComponent: 16
};
} else {
ReactTypeOfWork = {
IndeterminateComponent: 0,
FunctionalComponent: 1,
FunctionalComponentLazy: -1, // Doesn't exist yet
ClassComponent: 2,
ClassComponentLazy: -1, // Doesn't exist yet
HostRoot: 3,
HostPortal: 4,
HostComponent: 5,
HostText: 6,
CoroutineComponent: 7,
CoroutineHandlerPhase: 8,
YieldComponent: 9,
Fragment: 10,
Mode: 11,
ContextConsumer: 12,
ContextProvider: 13,
ForwardRef: 14,
ForwardRefLazy: -1, // Doesn't exist yet
Profiler: 15,
Placeholder: 16
};
}
ReactSymbols = {
ASYNC_MODE_NUMBER: 0xeacf,
ASYNC_MODE_SYMBOL_STRING: 'Symbol(react.async_mode)',
CONTEXT_CONSUMER_NUMBER: 0xeace,
CONTEXT_CONSUMER_SYMBOL_STRING: 'Symbol(react.context)',
CONTEXT_PROVIDER_NUMBER: 0xeacd,
CONTEXT_PROVIDER_SYMBOL_STRING: 'Symbol(react.provider)',
FORWARD_REF_NUMBER: 0xead0,
FORWARD_REF_SYMBOL_STRING: 'Symbol(react.forward_ref)',
PROFILER_NUMBER: 0xead2,
PROFILER_SYMBOL_STRING: 'Symbol(react.profiler)',
STRICT_MODE_NUMBER: 0xeacc,
STRICT_MODE_SYMBOL_STRING: 'Symbol(react.strict_mode)',
PLACEHOLDER_NUMBER: 0xead1,
PLACEHOLDER_SYMBOL_STRING: 'Symbol(react.placeholder)'
};
ReactTypeOfSideEffect = {
PerformedWork: 1
};
// **********************************************************
// End of copy paste.
// **********************************************************
return {
ReactTypeOfWork: ReactTypeOfWork,
ReactSymbols: ReactSymbols,
ReactTypeOfSideEffect: ReactTypeOfSideEffect
};
}
function attachRendererFiber(hook, rid, renderer) {
var _getInternalReactCons = getInternalReactConstants(renderer.version),
ReactTypeOfWork = _getInternalReactCons.ReactTypeOfWork,
ReactSymbols = _getInternalReactCons.ReactSymbols,
ReactTypeOfSideEffect = _getInternalReactCons.ReactTypeOfSideEffect;
var PerformedWork = ReactTypeOfSideEffect.PerformedWork;
var FunctionalComponent = ReactTypeOfWork.FunctionalComponent,
FunctionalComponentLazy = ReactTypeOfWork.FunctionalComponentLazy,
ClassComponent = ReactTypeOfWork.ClassComponent,
ClassComponentLazy = ReactTypeOfWork.ClassComponentLazy,
ContextConsumer = ReactTypeOfWork.ContextConsumer,
HostRoot = ReactTypeOfWork.HostRoot,
HostPortal = ReactTypeOfWork.HostPortal,
HostComponent = ReactTypeOfWork.HostComponent,
HostText = ReactTypeOfWork.HostText,
Fragment = ReactTypeOfWork.Fragment,
ForwardRef = ReactTypeOfWork.ForwardRef,
ForwardRefLazy = ReactTypeOfWork.ForwardRefLazy;
var ASYNC_MODE_NUMBER = ReactSymbols.ASYNC_MODE_NUMBER,
ASYNC_MODE_SYMBOL_STRING = ReactSymbols.ASYNC_MODE_SYMBOL_STRING,
CONTEXT_CONSUMER_NUMBER = ReactSymbols.CONTEXT_CONSUMER_NUMBER,
CONTEXT_CONSUMER_SYMBOL_STRING = ReactSymbols.CONTEXT_CONSUMER_SYMBOL_STRING,
CONTEXT_PROVIDER_NUMBER = ReactSymbols.CONTEXT_PROVIDER_NUMBER,
CONTEXT_PROVIDER_SYMBOL_STRING = ReactSymbols.CONTEXT_PROVIDER_SYMBOL_STRING,
PROFILER_NUMBER = ReactSymbols.PROFILER_NUMBER,
PROFILER_SYMBOL_STRING = ReactSymbols.PROFILER_SYMBOL_STRING,
STRICT_MODE_NUMBER = ReactSymbols.STRICT_MODE_NUMBER,
STRICT_MODE_SYMBOL_STRING = ReactSymbols.STRICT_MODE_SYMBOL_STRING,
PLACEHOLDER_NUMBER = ReactSymbols.PLACEHOLDER_NUMBER,
PLACEHOLDER_SYMBOL_STRING = ReactSymbols.PLACEHOLDER_SYMBOL_STRING;
// TODO: we might want to change the data structure
// once we no longer suppport Stack versions of `getData`.
function getDataFiber(fiber) {
var type = fiber.type;
var key = fiber.key;
var ref = fiber.ref;
var source = fiber._debugSource;
var publicInstance = null;
var props = null;
var state = null;
var children = null;
var context = null;
var updater = null;
var nodeType = null;
var name = null;
var text = null;
// Profiler data
var actualDuration = null;
var actualStartTime = null;
var treeBaseDuration = null;
var resolvedType = type;
if ((typeof type === 'undefined' ? 'undefined' : _typeof(type)) === 'object' && type !== null) {
if (typeof type.then === 'function') {
resolvedType = type._reactResult;
}
}
switch (fiber.tag) {
case FunctionalComponent:
case FunctionalComponentLazy:
case ClassComponent:
case ClassComponentLazy:
nodeType = 'Composite';
name = getDisplayName(resolvedType);
publicInstance = fiber.stateNode;
props = fiber.memoizedProps;
state = fiber.memoizedState;
if (publicInstance != null) {
context = publicInstance.context;
if (context && Object.keys(context).length === 0) {
context = null;
}
}
var inst = publicInstance;
if (inst) {
updater = {
setState: inst.setState && inst.setState.bind(inst),
forceUpdate: inst.forceUpdate && inst.forceUpdate.bind(inst),
setInProps: inst.forceUpdate && setInProps.bind(null, fiber),
setInState: inst.forceUpdate && setInState.bind(null, inst),
setInContext: inst.forceUpdate && setInContext.bind(null, inst)
};
}
children = [];
break;
case ForwardRef:
case ForwardRefLazy:
var functionName = getDisplayName(resolvedType.render, '');
nodeType = 'Special';
name = functionName !== '' ? 'ForwardRef(' + functionName + ')' : 'ForwardRef';
children = [];
break;
case HostRoot:
nodeType = 'Wrapper';
children = [];
break;
case HostPortal:
nodeType = 'Portal';
name = 'ReactPortal';
props = {
target: fiber.stateNode.containerInfo
};
children = [];
break;
case HostComponent:
nodeType = 'Native';
name = fiber.type;
// TODO (bvaughn) we plan to remove this prefix anyway.
// We can cut this special case out when it's gone.
name = name.replace('topsecret-', '');
publicInstance = fiber.stateNode;
props = fiber.memoizedProps;
if (typeof props.children === 'string' || typeof props.children === 'number') {
children = props.children.toString();
} else {
children = [];
}
if (typeof fiber.stateNode.setNativeProps === 'function') {
// For editing styles in RN
updater = {
setNativeProps: function setNativeProps(nativeProps) {
fiber.stateNode.setNativeProps(nativeProps);
}
};
}
break;
case HostText:
nodeType = 'Text';
text = fiber.memoizedProps;
break;
case Fragment:
nodeType = 'Wrapper';
children = [];
break;
default:
var symbolOrNumber = (typeof type === 'undefined' ? 'undefined' : _typeof(type)) === 'object' && type !== null ? type.$$typeof : type;
// $FlowFixMe facebook/flow/issues/2362
var switchValue = (typeof symbolOrNumber === 'undefined' ? 'undefined' : _typeof(symbolOrNumber)) === 'symbol' ? symbolOrNumber.toString() : symbolOrNumber;
switch (switchValue) {
case ASYNC_MODE_NUMBER:
case ASYNC_MODE_SYMBOL_STRING:
nodeType = 'Special';
name = 'AsyncMode';
children = [];
break;
case CONTEXT_PROVIDER_NUMBER:
case CONTEXT_PROVIDER_SYMBOL_STRING:
nodeType = 'Special';
props = fiber.memoizedProps;
name = (fiber.type._context.displayName || 'Context') + '.Provider';
children = [];
break;
case CONTEXT_CONSUMER_NUMBER:
case CONTEXT_CONSUMER_SYMBOL_STRING:
nodeType = 'Special';
props = fiber.memoizedProps;
// NOTE: TraceUpdatesBackendManager depends on the name ending in '.Consumer'
// If you change the name, figure out a more resilient way to detect it.
name = (fiber.type.displayName || 'Context') + '.Consumer';
children = [];
break;
case STRICT_MODE_NUMBER:
case STRICT_MODE_SYMBOL_STRING:
nodeType = 'Special';
name = 'StrictMode';
children = [];
break;
case PLACEHOLDER_NUMBER:
case PLACEHOLDER_SYMBOL_STRING:
nodeType = 'Special';
name = 'Placeholder';
props = fiber.memoizedProps;
children = [];
break;
case PROFILER_NUMBER:
case PROFILER_SYMBOL_STRING:
nodeType = 'Special';
props = fiber.memoizedProps;
name = 'Profiler(' + fiber.memoizedProps.id + ')';
children = [];
break;
default:
nodeType = 'Native';
props = fiber.memoizedProps;
name = 'TODO_NOT_IMPLEMENTED_YET';
children = [];
break;
}
break;
}
if (Array.isArray(children)) {
var child = fiber.child;
while (child) {
children.push(getOpaqueNode(child));
child = child.sibling;
}
}
if (fiber.actualDuration !== undefined) {
actualDuration = fiber.actualDuration;
actualStartTime = fiber.actualStartTime;
treeBaseDuration = fiber.treeBaseDuration;
}
// $FlowFixMe
return {
nodeType: nodeType,
type: type,
key: key,
ref: ref,
source: source,
name: name,
props: props,
state: state,
context: context,
children: children,
text: text,
updater: updater,
publicInstance: publicInstance,
// Profiler data
actualDuration: actualDuration,
actualStartTime: actualStartTime,
treeBaseDuration: treeBaseDuration
};
}
function setInProps(fiber, path, value) {
var inst = fiber.stateNode;
fiber.pendingProps = copyWithSet(inst.props, path, value);
if (fiber.alternate) {
// We don't know which fiber is the current one because DevTools may bail out of getDataFiber() call,
// and so the data object may refer to another version of the fiber. Therefore we update pendingProps
// on both. I hope that this is safe.
fiber.alternate.pendingProps = fiber.pendingProps;
}
fiber.stateNode.forceUpdate();
}
function setInState(inst, path, value) {
setIn(inst.state, path, value);
inst.forceUpdate();
}
function setInContext(inst, path, value) {
setIn(inst.context, path, value);
inst.forceUpdate();
}
function setIn(obj, path, value) {
var last = path.pop();
var parent = path.reduce(function (obj_, attr) {
return obj_ ? obj_[attr] : null;
}, obj);
if (parent) {
parent[last] = value;
}
}
// This is a slightly annoying indirection.

@@ -47,23 +392,24 @@ // It is currently necessary because DevTools wants

function hasDataChanged(prevFiber, nextFiber) {
if (prevFiber.tag === ClassComponent) {
// Skip if the class performed no work (shouldComponentUpdate bailout).
// eslint-disable-next-line no-bitwise
if ((nextFiber.effectTag & PerformedWork) !== PerformedWork) {
return false;
}
// Only classes have context.
if (prevFiber.stateNode.context !== nextFiber.stateNode.context) {
return true;
}
// Force updating won't update state or props.
if (nextFiber.updateQueue != null && nextFiber.updateQueue.hasForceUpdate) {
return true;
}
switch (nextFiber.tag) {
case ClassComponent:
case FunctionalComponent:
case ContextConsumer:
// For types that execute user code, we check PerformedWork effect.
// We don't reflect bailouts (either referential or sCU) in DevTools.
// eslint-disable-next-line no-bitwise
return (nextFiber.effectTag & PerformedWork) === PerformedWork;
// Note: ContextConsumer only gets PerformedWork effect in 16.3.3+
// so it won't get highlighted with React 16.3.0 to 16.3.2.
default:
// For host components and other types, we compare inputs
// to determine whether something is an update.
return prevFiber.memoizedProps !== nextFiber.memoizedProps || prevFiber.memoizedState !== nextFiber.memoizedState || prevFiber.ref !== nextFiber.ref;
}
// Compare the fields that would result in observable changes in DevTools.
// We don't compare type, tag, index, and key, because these are known to match.
return prevFiber.memoizedProps !== nextFiber.memoizedProps || prevFiber.memoizedState !== nextFiber.memoizedState || prevFiber.ref !== nextFiber.ref || prevFiber._debugSource !== nextFiber._debugSource;
}
function haveProfilerTimesChanged(prevFiber, nextFiber) {
return prevFiber.actualDuration !== undefined && ( // Short-circuit check for non-profiling builds
prevFiber.actualDuration !== nextFiber.actualDuration || prevFiber.actualStartTime !== nextFiber.actualStartTime || prevFiber.treeBaseDuration !== nextFiber.treeBaseDuration);
}
var pendingEvents = [];

@@ -83,3 +429,3 @@

internalInstance: getOpaqueNode(fiber),
data: getDataFiber(fiber, getOpaqueNode),
data: getDataFiber(fiber),
renderer: rid,

@@ -101,2 +447,14 @@ type: 'mount'

if (!hasChildOrderChanged && !hasDataChanged(fiber.alternate, fiber)) {
// If only timing information has changed, we still need to update the nodes.
// But we can do it in a faster way since we know it's safe to skip the children.
// It's also important to avoid emitting an "update" signal for the node in this case,
// Since that would indicate to the Profiler that it was part of the "commit" when it wasn't.
if (haveProfilerTimesChanged(fiber.alternate, fiber)) {
pendingEvents.push({
internalInstance: getOpaqueNode(fiber),
data: getDataFiber(fiber),
renderer: rid,
type: 'updateProfileTimes'
});
}
return;

@@ -106,3 +464,3 @@ }

internalInstance: getOpaqueNode(fiber),
data: getDataFiber(fiber, getOpaqueNode),
data: getDataFiber(fiber),
renderer: rid,

@@ -133,2 +491,10 @@ type: 'update'

function markRootCommitted(fiber) {
pendingEvents.push({
internalInstance: getOpaqueNode(fiber),
renderer: rid,
type: 'rootCommitted'
});
}
function mountFiber(fiber) {

@@ -216,2 +582,3 @@ // Depth-first.

mountFiber(root.current);
markRootCommitted(root.current);
});

@@ -236,2 +603,3 @@ flushPendingEvents();

var alternate = current.alternate;
if (alternate) {

@@ -255,2 +623,3 @@ // TODO: relying on this seems a bit fishy.

}
markRootCommitted(current);
// We're done here.

@@ -257,0 +626,0 @@ flushPendingEvents();

@@ -13,2 +13,7 @@ /**

// ----------------------------------------------------
// This is Stack-only version.
// The Fiber version is inlined in attachRendererFiber.
// ----------------------------------------------------
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

@@ -20,2 +25,3 @@

var getDisplayName = require('./getDisplayName');
var traverseAllChildrenImpl = require('./traverseAllChildrenImpl');

@@ -60,5 +66,26 @@ /**

// This is a native node without rendered children -- meaning the children
// prop is just a string or (in the case of the <option>) a list of
// strings & numbers.
children = internalInstance._currentElement.props.children;
// prop is the unfiltered list of children.
// This may include 'null' or even other invalid values, so we need to
// filter it the same way that ReactDOM does.
// Instead of pulling in the whole React library, we just copied over the
// 'traverseAllChildrenImpl' method.
// https://github.com/facebook/react/blob/240b84ed8e1db715d759afaae85033718a0b24e1/src/isomorphic/children/ReactChildren.js#L112-L158
var unfilteredChildren = internalInstance._currentElement.props.children;
var filteredChildren = [];
traverseAllChildrenImpl(unfilteredChildren, '', // nameSoFar
function (_traverseContext, child) {
var childType = typeof child === 'undefined' ? 'undefined' : _typeof(child);
if (childType === 'string' || childType === 'number') {
filteredChildren.push(child);
}
}
// traverseContext
);
if (filteredChildren.length <= 1) {
// children must be an array of nodes or a string or undefined
// can't be an empty array
children = filteredChildren.length ? String(filteredChildren[0]) : undefined;
} else {
children = filteredChildren;
}
}

@@ -107,8 +134,13 @@

var inst = internalInstance._instance;
// A forceUpdate for stateless (functional) components.
var forceUpdate = inst.forceUpdate || inst.updater && inst.updater.enqueueForceUpdate && function (cb) {
inst.updater.enqueueForceUpdate(this, cb, 'forceUpdate');
};
updater = {
setState: inst.setState && inst.setState.bind(inst),
forceUpdate: inst.forceUpdate && inst.forceUpdate.bind(inst),
setInProps: inst.forceUpdate && setInProps.bind(null, internalInstance),
forceUpdate: forceUpdate && forceUpdate.bind(inst),
setInProps: forceUpdate && setInProps.bind(null, internalInstance, forceUpdate),
setInState: inst.forceUpdate && setInState.bind(null, inst),
setInContext: inst.forceUpdate && setInContext.bind(null, inst)
setInContext: forceUpdate && setInContext.bind(null, inst, forceUpdate)
};

@@ -136,2 +168,3 @@ if (typeof type === 'function') {

// $FlowFixMe
return {

@@ -154,3 +187,3 @@ nodeType: nodeType,

function setInProps(internalInst, path, value) {
function setInProps(internalInst, forceUpdate, path, value) {
var element = internalInst._currentElement;

@@ -160,3 +193,3 @@ internalInst._currentElement = _extends({}, element, {

});
internalInst._instance.forceUpdate();
forceUpdate.call(internalInst._instance);
}

@@ -169,5 +202,5 @@

function setInContext(inst, path, value) {
function setInContext(inst, forceUpdate, path, value) {
setIn(inst.context, path, value);
inst.forceUpdate();
forceUpdate.call(inst);
}

@@ -174,0 +207,0 @@

@@ -13,2 +13,7 @@ /**

// ----------------------------------------------------
// This is Stack-only version.
// The Fiber version is inlined in attachRendererFiber.
// ----------------------------------------------------
var copyWithSet = require('./copyWithSet');

@@ -89,2 +94,3 @@

// $FlowFixMe
return {

@@ -91,0 +97,0 @@ nodeType: nodeType,

@@ -17,4 +17,7 @@ /**

function getDisplayName(type) {
if (cachedDisplayNames.has(type)) {
return cachedDisplayNames.get(type);
var fallbackName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'Unknown';
var nameFromCache = cachedDisplayNames.get(type);
if (nameFromCache != null) {
return nameFromCache;
}

@@ -32,3 +35,3 @@

if (!displayName) {
displayName = type.name || 'Unknown';
displayName = type.name || fallbackName;
}

@@ -35,0 +38,0 @@

@@ -23,3 +23,2 @@ /**

try {
var toString = Function.prototype.toString;
if (typeof renderer.version === 'string') {

@@ -33,25 +32,13 @@ // React DOM Fiber (16+)

}
// The above should cover envification, but we should still make sure
// that the bundle code has been uglified.
var findFiberCode = toString.call(renderer.findFiberByHostInstance);
// Filter out bad results (if that is even possible):
if (findFiberCode.indexOf('function') !== 0) {
// Hope for the best if we're not sure.
return 'production';
}
// By now we know that it's envified--but what if it's not minified?
// This can be bad too, as it means DEV code is still there.
// FIXME: this is fragile!
// We should replace this check with check on a specially passed
// function. This also doesn't detect lack of dead code elimination
// (although this is not a problem since flat bundles).
if (findFiberCode.indexOf('getClosestInstanceFromNode') !== -1) {
return 'unminified';
}
// We're good.
// React 16 uses flat bundles. If we report the bundle as production
// version, it means we also minified and envified it ourselves.
return 'production';
// Note: There is still a risk that the CommonJS entry point has not
// been envified or uglified. In this case the user would have *both*
// development and production bundle, but only the prod one would run.
// This would be really bad. We have a separate check for this because
// it happens *outside* of the renderer injection. See `checkDCE` below.
}
var toString = Function.prototype.toString;
if (renderer.Mount && renderer.Mount._renderNewRootComponent) {

@@ -122,13 +109,4 @@ // React DOM Stack

// Seems like we're using the production version.
// Now let's check if we're still on 0.14 or lower:
if (renderRootCode.indexOf('._registerComponent') !== -1) {
// TODO: we can remove the condition above once 16
// is older than a year. Since this branch only runs
// for Stack, we can flip it completely when Stack
// is old enough. The branch for Fiber is above,
// and it can check renderer.version directly.
return 'outdated';
}
// We're all good.
return 'production';
// However, the branch above is Stack-only so this is 15 or earlier.
return 'outdated';
}

@@ -143,2 +121,5 @@ } catch (err) {

}
var hasDetectedBadDCE = false;
var hook = {

@@ -148,6 +129,27 @@ // Shared between Stack and Fiber:

helpers: {},
checkDCE: function checkDCE(fn) {
// This runs for production versions of React.
// Needs to be super safe.
try {
var toString = Function.prototype.toString;
var code = toString.call(fn);
// This is a string embedded in the passed function under DEV-only
// condition. However the function executes only in PROD. Therefore,
// if we see it, dead code elimination did not work.
if (code.indexOf('^_^') > -1) {
// Remember to report during next injection.
hasDetectedBadDCE = true;
// Bonus: throw an exception hoping that it gets picked up by
// a reporting system. Not synchronously so that it doesn't break the
// calling code.
setTimeout(function () {
throw new Error('React is running in production mode, but dead code ' + 'elimination has not been applied. Read how to correctly ' + 'configure React for production: ' + 'https://fb.me/react-perf-use-the-production-build');
});
}
} catch (err) {}
},
inject: function inject(renderer) {
var id = Math.random().toString(16).slice(2);
hook._renderers[id] = renderer;
var reactBuildType = detectReactBuildType(renderer);
var reactBuildType = hasDetectedBadDCE ? 'deadcode' : detectReactBuildType(renderer);
hook.emit('renderer', { id: id, renderer: renderer, reactBuildType: reactBuildType });

@@ -154,0 +156,0 @@ return id;

{
"name": "react-render-hook",
"version": "1.0.1",
"version": "1.1.0",
"description": "Hooks to React.js rendering, to enable access to the virtual DOM (as shown in React devtools)",

@@ -36,4 +36,4 @@ "scripts": {

"object-assign": "^4.0.1",
"react": "^16.0.0-rc",
"react-dom": "^16.0.0-rc",
"react": "^16.5.2",
"react-dom": "^16.5.2",
"unexpected": "^10.0.2"

@@ -47,3 +47,6 @@ },

"src/react-devtools/backend/*.js"
]
],
"dependencies": {
"semver": "^5.5.1"
}
}

@@ -65,5 +65,7 @@ /**

extras.getReactElementFromNative = function(node) {
// $FlowFixMe
var id = renderer.Mount.getID(node);
while (node && node.parentNode && !id) {
node = node.parentNode;
// $FlowFixMe
id = renderer.Mount.getID(node);

@@ -116,3 +118,3 @@ }

hook.emit('unmount', {internalInstance: this, renderer: rid});
rootNodeIDMap.delete(this._rootNodeID, this);
rootNodeIDMap.delete(this._rootNodeID);
},

@@ -135,3 +137,3 @@ });

hook.emit('unmount', {internalInstance, renderer: rid});
rootNodeIDMap.delete(internalInstance._rootNodeID, internalInstance);
rootNodeIDMap.delete(internalInstance._rootNodeID);
},

@@ -138,0 +140,0 @@ });

@@ -13,13 +13,363 @@ /**

import type {Hook, ReactRenderer, Helpers} from './types';
var getDataFiber = require('./getDataFiber');
var {
ClassComponent,
HostRoot,
} = require('./ReactTypeOfWork');
import type {Hook, ReactRenderer, DataType, Helpers} from './types';
// Inlined from ReactTypeOfSideEffect
var PerformedWork = 1;
var semver = require('semver');
var copyWithSet = require('./copyWithSet');
var getDisplayName = require('./getDisplayName');
function getInternalReactConstants(version) {
var ReactTypeOfWork;
var ReactSymbols;
var ReactTypeOfSideEffect;
// **********************************************************
// The section below is copy-pasted from files in React repo.
// Keep it in sync, and add version guards if it changes.
// **********************************************************
if (semver.gte(version, '16.4.3-alpha')) {
ReactTypeOfWork = {
FunctionalComponent: 0,
FunctionalComponentLazy: 1,
ClassComponent: 2,
ClassComponentLazy: 3,
IndeterminateComponent: 4,
HostRoot: 5,
HostPortal: 6,
HostComponent: 7,
HostText: 8,
Fragment: 9,
Mode: 10,
ContextConsumer: 11,
ContextProvider: 12,
ForwardRef: 13,
ForwardRefLazy: 14,
Profiler: 15,
PlaceholderComponent: 16,
};
} else {
ReactTypeOfWork = {
IndeterminateComponent: 0,
FunctionalComponent: 1,
FunctionalComponentLazy: -1, // Doesn't exist yet
ClassComponent: 2,
ClassComponentLazy: -1, // Doesn't exist yet
HostRoot: 3,
HostPortal: 4,
HostComponent: 5,
HostText: 6,
CoroutineComponent: 7,
CoroutineHandlerPhase: 8,
YieldComponent: 9,
Fragment: 10,
Mode: 11,
ContextConsumer: 12,
ContextProvider: 13,
ForwardRef: 14,
ForwardRefLazy: -1, // Doesn't exist yet
Profiler: 15,
Placeholder: 16,
};
}
ReactSymbols = {
ASYNC_MODE_NUMBER: 0xeacf,
ASYNC_MODE_SYMBOL_STRING: 'Symbol(react.async_mode)',
CONTEXT_CONSUMER_NUMBER: 0xeace,
CONTEXT_CONSUMER_SYMBOL_STRING: 'Symbol(react.context)',
CONTEXT_PROVIDER_NUMBER: 0xeacd,
CONTEXT_PROVIDER_SYMBOL_STRING: 'Symbol(react.provider)',
FORWARD_REF_NUMBER: 0xead0,
FORWARD_REF_SYMBOL_STRING: 'Symbol(react.forward_ref)',
PROFILER_NUMBER: 0xead2,
PROFILER_SYMBOL_STRING: 'Symbol(react.profiler)',
STRICT_MODE_NUMBER: 0xeacc,
STRICT_MODE_SYMBOL_STRING: 'Symbol(react.strict_mode)',
PLACEHOLDER_NUMBER: 0xead1,
PLACEHOLDER_SYMBOL_STRING: 'Symbol(react.placeholder)',
};
ReactTypeOfSideEffect = {
PerformedWork: 1,
};
// **********************************************************
// End of copy paste.
// **********************************************************
return {
ReactTypeOfWork,
ReactSymbols,
ReactTypeOfSideEffect,
};
}
function attachRendererFiber(hook: Hook, rid: string, renderer: ReactRenderer): Helpers {
var {ReactTypeOfWork, ReactSymbols, ReactTypeOfSideEffect} = getInternalReactConstants(renderer.version);
var {PerformedWork} = ReactTypeOfSideEffect;
var {
FunctionalComponent,
FunctionalComponentLazy,
ClassComponent,
ClassComponentLazy,
ContextConsumer,
HostRoot,
HostPortal,
HostComponent,
HostText,
Fragment,
ForwardRef,
ForwardRefLazy,
} = ReactTypeOfWork;
var {
ASYNC_MODE_NUMBER,
ASYNC_MODE_SYMBOL_STRING,
CONTEXT_CONSUMER_NUMBER,
CONTEXT_CONSUMER_SYMBOL_STRING,
CONTEXT_PROVIDER_NUMBER,
CONTEXT_PROVIDER_SYMBOL_STRING,
PROFILER_NUMBER,
PROFILER_SYMBOL_STRING,
STRICT_MODE_NUMBER,
STRICT_MODE_SYMBOL_STRING,
PLACEHOLDER_NUMBER,
PLACEHOLDER_SYMBOL_STRING,
} = ReactSymbols;
// TODO: we might want to change the data structure
// once we no longer suppport Stack versions of `getData`.
function getDataFiber(fiber: Object): DataType {
var type = fiber.type;
var key = fiber.key;
var ref = fiber.ref;
var source = fiber._debugSource;
var publicInstance = null;
var props = null;
var state = null;
var children = null;
var context = null;
var updater = null;
var nodeType = null;
var name = null;
var text = null;
// Profiler data
var actualDuration = null;
var actualStartTime = null;
var treeBaseDuration = null;
var resolvedType = type;
if (typeof type === 'object' && type !== null) {
if (typeof type.then === 'function') {
resolvedType = type._reactResult;
}
}
switch (fiber.tag) {
case FunctionalComponent:
case FunctionalComponentLazy:
case ClassComponent:
case ClassComponentLazy:
nodeType = 'Composite';
name = getDisplayName(resolvedType);
publicInstance = fiber.stateNode;
props = fiber.memoizedProps;
state = fiber.memoizedState;
if (publicInstance != null) {
context = publicInstance.context;
if (context && Object.keys(context).length === 0) {
context = null;
}
}
const inst = publicInstance;
if (inst) {
updater = {
setState: inst.setState && inst.setState.bind(inst),
forceUpdate: inst.forceUpdate && inst.forceUpdate.bind(inst),
setInProps: inst.forceUpdate && setInProps.bind(null, fiber),
setInState: inst.forceUpdate && setInState.bind(null, inst),
setInContext: inst.forceUpdate && setInContext.bind(null, inst),
};
}
children = [];
break;
case ForwardRef:
case ForwardRefLazy:
const functionName = getDisplayName(resolvedType.render, '');
nodeType = 'Special';
name = functionName !== '' ? `ForwardRef(${functionName})` : 'ForwardRef';
children = [];
break;
case HostRoot:
nodeType = 'Wrapper';
children = [];
break;
case HostPortal:
nodeType = 'Portal';
name = 'ReactPortal';
props = {
target: fiber.stateNode.containerInfo,
};
children = [];
break;
case HostComponent:
nodeType = 'Native';
name = fiber.type;
// TODO (bvaughn) we plan to remove this prefix anyway.
// We can cut this special case out when it's gone.
name = name.replace('topsecret-', '');
publicInstance = fiber.stateNode;
props = fiber.memoizedProps;
if (
typeof props.children === 'string' ||
typeof props.children === 'number'
) {
children = props.children.toString();
} else {
children = [];
}
if (typeof fiber.stateNode.setNativeProps === 'function') {
// For editing styles in RN
updater = {
setNativeProps(nativeProps) {
fiber.stateNode.setNativeProps(nativeProps);
},
};
}
break;
case HostText:
nodeType = 'Text';
text = fiber.memoizedProps;
break;
case Fragment:
nodeType = 'Wrapper';
children = [];
break;
default:
const symbolOrNumber = typeof type === 'object' && type !== null
? type.$$typeof
: type;
// $FlowFixMe facebook/flow/issues/2362
const switchValue = typeof symbolOrNumber === 'symbol'
? symbolOrNumber.toString()
: symbolOrNumber;
switch (switchValue) {
case ASYNC_MODE_NUMBER:
case ASYNC_MODE_SYMBOL_STRING:
nodeType = 'Special';
name = 'AsyncMode';
children = [];
break;
case CONTEXT_PROVIDER_NUMBER:
case CONTEXT_PROVIDER_SYMBOL_STRING:
nodeType = 'Special';
props = fiber.memoizedProps;
name = `${fiber.type._context.displayName || 'Context'}.Provider`;
children = [];
break;
case CONTEXT_CONSUMER_NUMBER:
case CONTEXT_CONSUMER_SYMBOL_STRING:
nodeType = 'Special';
props = fiber.memoizedProps;
// NOTE: TraceUpdatesBackendManager depends on the name ending in '.Consumer'
// If you change the name, figure out a more resilient way to detect it.
name = `${fiber.type.displayName || 'Context'}.Consumer`;
children = [];
break;
case STRICT_MODE_NUMBER:
case STRICT_MODE_SYMBOL_STRING:
nodeType = 'Special';
name = 'StrictMode';
children = [];
break;
case PLACEHOLDER_NUMBER:
case PLACEHOLDER_SYMBOL_STRING:
nodeType = 'Special';
name = 'Placeholder';
props = fiber.memoizedProps;
children = [];
break;
case PROFILER_NUMBER:
case PROFILER_SYMBOL_STRING:
nodeType = 'Special';
props = fiber.memoizedProps;
name = `Profiler(${fiber.memoizedProps.id})`;
children = [];
break;
default:
nodeType = 'Native';
props = fiber.memoizedProps;
name = 'TODO_NOT_IMPLEMENTED_YET';
children = [];
break;
}
break;
}
if (Array.isArray(children)) {
let child = fiber.child;
while (child) {
children.push(getOpaqueNode(child));
child = child.sibling;
}
}
if (fiber.actualDuration !== undefined) {
actualDuration = fiber.actualDuration;
actualStartTime = fiber.actualStartTime;
treeBaseDuration = fiber.treeBaseDuration;
}
// $FlowFixMe
return {
nodeType,
type,
key,
ref,
source,
name,
props,
state,
context,
children,
text,
updater,
publicInstance,
// Profiler data
actualDuration,
actualStartTime,
treeBaseDuration,
};
}
function setInProps(fiber, path: Array<string | number>, value: any) {
const inst = fiber.stateNode;
fiber.pendingProps = copyWithSet(inst.props, path, value);
if (fiber.alternate) {
// We don't know which fiber is the current one because DevTools may bail out of getDataFiber() call,
// and so the data object may refer to another version of the fiber. Therefore we update pendingProps
// on both. I hope that this is safe.
fiber.alternate.pendingProps = fiber.pendingProps;
}
fiber.stateNode.forceUpdate();
}
function setInState(inst, path: Array<string | number>, value: any) {
setIn(inst.state, path, value);
inst.forceUpdate();
}
function setInContext(inst, path: Array<string | number>, value: any) {
setIn(inst.context, path, value);
inst.forceUpdate();
}
function setIn(obj: Object, path: Array<string | number>, value: any) {
var last = path.pop();
var parent = path.reduce((obj_, attr) => obj_ ? obj_[attr] : null, obj);
if (parent) {
parent[last] = value;
}
}
// This is a slightly annoying indirection.

@@ -45,25 +395,31 @@ // It is currently necessary because DevTools wants

function hasDataChanged(prevFiber, nextFiber) {
if (prevFiber.tag === ClassComponent) {
// Skip if the class performed no work (shouldComponentUpdate bailout).
// eslint-disable-next-line no-bitwise
if ((nextFiber.effectTag & PerformedWork) !== PerformedWork) {
return false;
}
switch (nextFiber.tag) {
case ClassComponent:
case FunctionalComponent:
case ContextConsumer:
// For types that execute user code, we check PerformedWork effect.
// We don't reflect bailouts (either referential or sCU) in DevTools.
// eslint-disable-next-line no-bitwise
return (nextFiber.effectTag & PerformedWork) === PerformedWork;
// Note: ContextConsumer only gets PerformedWork effect in 16.3.3+
// so it won't get highlighted with React 16.3.0 to 16.3.2.
default:
// For host components and other types, we compare inputs
// to determine whether something is an update.
return (
prevFiber.memoizedProps !== nextFiber.memoizedProps ||
prevFiber.memoizedState !== nextFiber.memoizedState ||
prevFiber.ref !== nextFiber.ref
);
}
}
// Only classes have context.
if (prevFiber.stateNode.context !== nextFiber.stateNode.context) {
return true;
}
// Force updating won't update state or props.
if (nextFiber.updateQueue != null && nextFiber.updateQueue.hasForceUpdate) {
return true;
}
}
// Compare the fields that would result in observable changes in DevTools.
// We don't compare type, tag, index, and key, because these are known to match.
function haveProfilerTimesChanged(prevFiber, nextFiber) {
return (
prevFiber.memoizedProps !== nextFiber.memoizedProps ||
prevFiber.memoizedState !== nextFiber.memoizedState ||
prevFiber.ref !== nextFiber.ref ||
prevFiber._debugSource !== nextFiber._debugSource
prevFiber.actualDuration !== undefined && // Short-circuit check for non-profiling builds
(
prevFiber.actualDuration !== nextFiber.actualDuration ||
prevFiber.actualStartTime !== nextFiber.actualStartTime ||
prevFiber.treeBaseDuration !== nextFiber.treeBaseDuration
)
);

@@ -86,3 +442,3 @@ }

internalInstance: getOpaqueNode(fiber),
data: getDataFiber(fiber, getOpaqueNode),
data: getDataFiber(fiber),
renderer: rid,

@@ -103,3 +459,18 @@ type: 'mount',

function enqueueUpdateIfNecessary(fiber, hasChildOrderChanged) {
if (!hasChildOrderChanged && !hasDataChanged(fiber.alternate, fiber)) {
if (
!hasChildOrderChanged &&
!hasDataChanged(fiber.alternate, fiber)
) {
// If only timing information has changed, we still need to update the nodes.
// But we can do it in a faster way since we know it's safe to skip the children.
// It's also important to avoid emitting an "update" signal for the node in this case,
// Since that would indicate to the Profiler that it was part of the "commit" when it wasn't.
if (haveProfilerTimesChanged(fiber.alternate, fiber)) {
pendingEvents.push({
internalInstance: getOpaqueNode(fiber),
data: getDataFiber(fiber),
renderer: rid,
type: 'updateProfileTimes',
});
}
return;

@@ -109,3 +480,3 @@ }

internalInstance: getOpaqueNode(fiber),
data: getDataFiber(fiber, getOpaqueNode),
data: getDataFiber(fiber),
renderer: rid,

@@ -136,2 +507,10 @@ type: 'update',

function markRootCommitted(fiber) {
pendingEvents.push({
internalInstance: getOpaqueNode(fiber),
renderer: rid,
type: 'rootCommitted',
});
}
function mountFiber(fiber) {

@@ -219,2 +598,3 @@ // Depth-first.

mountFiber(root.current);
markRootCommitted(root.current);
});

@@ -239,2 +619,3 @@ flushPendingEvents();

const alternate = current.alternate;
if (alternate) {

@@ -258,2 +639,3 @@ // TODO: relying on this seems a bit fishy.

}
markRootCommitted(current);
// We're done here.

@@ -260,0 +642,0 @@ flushPendingEvents();

@@ -13,5 +13,11 @@ /**

// ----------------------------------------------------
// This is Stack-only version.
// The Fiber version is inlined in attachRendererFiber.
// ----------------------------------------------------
import type {DataType} from './types';
var copyWithSet = require('./copyWithSet');
var getDisplayName = require('./getDisplayName');
var traverseAllChildrenImpl = require('./traverseAllChildrenImpl');

@@ -56,5 +62,30 @@ /**

// This is a native node without rendered children -- meaning the children
// prop is just a string or (in the case of the <option>) a list of
// strings & numbers.
children = internalInstance._currentElement.props.children;
// prop is the unfiltered list of children.
// This may include 'null' or even other invalid values, so we need to
// filter it the same way that ReactDOM does.
// Instead of pulling in the whole React library, we just copied over the
// 'traverseAllChildrenImpl' method.
// https://github.com/facebook/react/blob/240b84ed8e1db715d759afaae85033718a0b24e1/src/isomorphic/children/ReactChildren.js#L112-L158
const unfilteredChildren = internalInstance._currentElement.props.children;
var filteredChildren = [];
traverseAllChildrenImpl(
unfilteredChildren,
'', // nameSoFar
(_traverseContext, child) => {
const childType = typeof child;
if (childType === 'string' || childType === 'number') {
filteredChildren.push(child);
}
},
// traverseContext
);
if (filteredChildren.length <= 1) {
// children must be an array of nodes or a string or undefined
// can't be an empty array
children = filteredChildren.length
? String(filteredChildren[0])
: undefined;
} else {
children = filteredChildren;
}
}

@@ -106,8 +137,13 @@

var inst = internalInstance._instance;
// A forceUpdate for stateless (functional) components.
var forceUpdate = inst.forceUpdate || (inst.updater && inst.updater.enqueueForceUpdate && function(cb) {
inst.updater.enqueueForceUpdate(this, cb, 'forceUpdate');
});
updater = {
setState: inst.setState && inst.setState.bind(inst),
forceUpdate: inst.forceUpdate && inst.forceUpdate.bind(inst),
setInProps: inst.forceUpdate && setInProps.bind(null, internalInstance),
forceUpdate: forceUpdate && forceUpdate.bind(inst),
setInProps: forceUpdate && setInProps.bind(null, internalInstance, forceUpdate),
setInState: inst.forceUpdate && setInState.bind(null, inst),
setInContext: inst.forceUpdate && setInContext.bind(null, inst),
setInContext: forceUpdate && setInContext.bind(null, inst, forceUpdate),
};

@@ -135,2 +171,3 @@ if (typeof type === 'function') {

// $FlowFixMe
return {

@@ -153,3 +190,3 @@ nodeType,

function setInProps(internalInst, path: Array<string | number>, value: any) {
function setInProps(internalInst, forceUpdate, path: Array<string | number>, value: any) {
var element = internalInst._currentElement;

@@ -160,3 +197,3 @@ internalInst._currentElement = {

};
internalInst._instance.forceUpdate();
forceUpdate.call(internalInst._instance);
}

@@ -169,5 +206,5 @@

function setInContext(inst, path: Array<string | number>, value: any) {
function setInContext(inst, forceUpdate, path: Array<string | number>, value: any) {
setIn(inst.context, path, value);
inst.forceUpdate();
forceUpdate.call(inst);
}

@@ -174,0 +211,0 @@

@@ -13,2 +13,7 @@ /**

// ----------------------------------------------------
// This is Stack-only version.
// The Fiber version is inlined in attachRendererFiber.
// ----------------------------------------------------
import type {DataType} from './types';

@@ -90,2 +95,3 @@ var copyWithSet = require('./copyWithSet');

// $FlowFixMe
return {

@@ -92,0 +98,0 @@ nodeType,

@@ -14,7 +14,8 @@ /**

const FB_MODULE_RE = /^(.*) \[from (.*)\]$/;
const cachedDisplayNames = new WeakMap();
const cachedDisplayNames: WeakMap<Function, string> = new WeakMap();
function getDisplayName(type: Function): string {
if (cachedDisplayNames.has(type)) {
return cachedDisplayNames.get(type);
function getDisplayName(type: Function, fallbackName: string = 'Unknown'): string {
const nameFromCache = cachedDisplayNames.get(type);
if (nameFromCache != null) {
return nameFromCache;
}

@@ -32,3 +33,3 @@

if (!displayName) {
displayName = type.name || 'Unknown';
displayName = type.name || fallbackName;
}

@@ -35,0 +36,0 @@

@@ -25,3 +25,2 @@ /**

try {
var toString = Function.prototype.toString;
if (typeof renderer.version === 'string') {

@@ -35,25 +34,13 @@ // React DOM Fiber (16+)

}
// The above should cover envification, but we should still make sure
// that the bundle code has been uglified.
var findFiberCode = toString.call(renderer.findFiberByHostInstance);
// Filter out bad results (if that is even possible):
if (findFiberCode.indexOf('function') !== 0) {
// Hope for the best if we're not sure.
return 'production';
}
// By now we know that it's envified--but what if it's not minified?
// This can be bad too, as it means DEV code is still there.
// FIXME: this is fragile!
// We should replace this check with check on a specially passed
// function. This also doesn't detect lack of dead code elimination
// (although this is not a problem since flat bundles).
if (findFiberCode.indexOf('getClosestInstanceFromNode') !== -1) {
return 'unminified';
}
// We're good.
// React 16 uses flat bundles. If we report the bundle as production
// version, it means we also minified and envified it ourselves.
return 'production';
// Note: There is still a risk that the CommonJS entry point has not
// been envified or uglified. In this case the user would have *both*
// development and production bundle, but only the prod one would run.
// This would be really bad. We have a separate check for this because
// it happens *outside* of the renderer injection. See `checkDCE` below.
}
var toString = Function.prototype.toString;
if (renderer.Mount && renderer.Mount._renderNewRootComponent) {

@@ -126,13 +113,4 @@ // React DOM Stack

// Seems like we're using the production version.
// Now let's check if we're still on 0.14 or lower:
if (renderRootCode.indexOf('._registerComponent') !== -1) {
// TODO: we can remove the condition above once 16
// is older than a year. Since this branch only runs
// for Stack, we can flip it completely when Stack
// is old enough. The branch for Fiber is above,
// and it can check renderer.version directly.
return 'outdated';
}
// We're all good.
return 'production';
// However, the branch above is Stack-only so this is 15 or earlier.
return 'outdated';
}

@@ -147,2 +125,5 @@ } catch (err) {

}
let hasDetectedBadDCE = false;
const hook = ({

@@ -152,6 +133,34 @@ // Shared between Stack and Fiber:

helpers: {},
checkDCE: function(fn) {
// This runs for production versions of React.
// Needs to be super safe.
try {
var toString = Function.prototype.toString;
var code = toString.call(fn);
// This is a string embedded in the passed function under DEV-only
// condition. However the function executes only in PROD. Therefore,
// if we see it, dead code elimination did not work.
if (code.indexOf('^_^') > -1) {
// Remember to report during next injection.
hasDetectedBadDCE = true;
// Bonus: throw an exception hoping that it gets picked up by
// a reporting system. Not synchronously so that it doesn't break the
// calling code.
setTimeout(function() {
throw new Error(
'React is running in production mode, but dead code ' +
'elimination has not been applied. Read how to correctly ' +
'configure React for production: ' +
'https://fb.me/react-perf-use-the-production-build'
);
});
}
} catch (err) { }
},
inject: function(renderer) {
var id = Math.random().toString(16).slice(2);
hook._renderers[id] = renderer;
var reactBuildType = detectReactBuildType(renderer);
var reactBuildType = hasDetectedBadDCE ?
'deadcode' :
detectReactBuildType(renderer);
hook.emit('renderer', {id, renderer, reactBuildType});

@@ -158,0 +167,0 @@ return id;

@@ -25,3 +25,3 @@ /**

export type DataType = {
nodeType: 'Native' | 'Wrapper' | 'NativeWrapper' | 'Composite' | 'Text' | 'Portal' | 'Empty',
nodeType: 'Native' | 'Wrapper' | 'NativeWrapper' | 'Composite' | 'Special' | 'Text' | 'Portal' | 'Empty',
type: ?(string | AnyFn),

@@ -28,0 +28,0 @@ key: ?string,

@@ -81,2 +81,4 @@ # React Developer Tools [![Build Status](https://travis-ci.org/facebook/react-devtools.svg?branch=master)](https://travis-ci.org/facebook/react-devtools)

Or you could develop with a local HTTP server [like `serve`](https://www.npmjs.com/package/serve).
**The React tab won't show up if the site doesn't use React**, or if React can't communicate with the devtools. When the page loads, the devtools sets a global named `__REACT_DEVTOOLS_GLOBAL_HOOK__`, then React communicates with that hook during initialization. You can test this on the [React website](http://facebook.github.io/react/) or by inspecting [Facebook](https://www.facebook.com/).

@@ -92,10 +94,5 @@

Yes, but it's also tracing if a component *may* render.
In order to fully understand what counts as an "update", you need to understand how [shouldComponentUpdate](https://facebook.github.io/react/docs/advanced-performance.html#shouldcomponentupdate-in-action) works.
![](https://facebook.github.io/react/img/docs/should-component-update.png)
With React 15 and earlier, "Highlight Updates" had false positives and highlighted more components than were actually re-rendering.
Here "Highlight Updates" will draw a border around every node but C4 and C5.
Why does it trace components that don't actually update? (via shouldComponentUpdate() -> false)
This is a limitation of the system used to track updates, and will hopefully change in the future. It doesn't, however, trace the children of components that opt out, as there's no possibility of them updating.
The higher the rate of updates happening per second the more the color changes from blue to red.
Since React 16, it correctly highlights only components that were re-rendered.

@@ -102,0 +99,0 @@ ## Contributing

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc