mirror of
https://github.com/hanzoai/react.git
synced 2026-09-24 17:02:27 +00:00
Refactor Debug Frames to Enable Renderers to Provide Custom Logic (#10105)
* Extract the top element frame from ReactDebugCurrentFrame This is part of a larger refactor to decouple stack addendums. All renderers have their own way of getting the stack of the currently executing components. There is one special case in Element Validator that adds an additional line for the element being validated. This commit moves that special case in into the validator. There is another case where it looked like this was used in shallow renderer but this is actually something different. It is part of the component stack. It just happens to be that shallow renderer has a simpler implementation of the component stack that just happens to be a single element. This will let us decouple the implementation to get a stack from ReactDebugCurrentFrame and put that in each renderer. * Stop using ReactComponentTreeHook for Fiber Currently we fall back to ReactCurrentOwner in ReactComponentTreeHook for stack addendums. We shouldn't need to because we should use ReactDebugCurrrentFiber. Ensure we always set both ReactDebugCurrentFiber and ReactDebugCurrentFrame so that we can rely on these for all stacks. * Make ReactDebugCurrentFrame implementation independent Introduced ReactDebugCurrentStack for the Stack renderer which does the same thing as ReactDebugCurrentFiber. ReactDebugCurrentFrame no longer keeps track of the current fiber/debug id. That's handled by the individual renderers. Instead, it is now used to keep track of the current *implementation* of the current stack frame. That way it is decoupled from the specifics of the renderers. There can be multiple renderers in a context. What matters is which one is currently executing a debuggable context (such as a render function). * Add debug frames to ReactPartialRenderer (ssr) Basic functionality. * Add shared modules to shallow renderer This is now needed because we share describeComponentFrame.
This commit is contained in:
committed by
GitHub
parent
641c88e4cd
commit
4165e851c5
@@ -1,5 +1,2 @@
|
||||
src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
|
||||
* gives source code refs for unknown prop warning (ssr)
|
||||
* gives source code refs for unknown prop warning for exact elements (ssr)
|
||||
* gives source code refs for unknown prop warning for exact elements in composition (ssr)
|
||||
* should suggest property name if available (ssr)
|
||||
|
||||
@@ -853,10 +853,13 @@ src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
|
||||
* should warn about props that are no longer supported
|
||||
* should warn about props that are no longer supported (ssr)
|
||||
* gives source code refs for unknown prop warning
|
||||
* gives source code refs for unknown prop warning (ssr)
|
||||
* gives source code refs for unknown prop warning for update render
|
||||
* gives source code refs for unknown prop warning for exact elements
|
||||
* gives source code refs for unknown prop warning for exact elements (ssr)
|
||||
* gives source code refs for unknown prop warning for exact elements in composition
|
||||
* should suggest property name if available
|
||||
* should suggest property name if available (ssr)
|
||||
* renders innerHTML and preserves whitespace
|
||||
* render and then updates innerHTML and preserves whitespace
|
||||
|
||||
|
||||
@@ -381,7 +381,11 @@ const bundles = [
|
||||
label: 'shallow-renderer',
|
||||
manglePropertiesOnProd: false,
|
||||
name: 'react-test-renderer/shallow',
|
||||
paths: ['src/renderers/shared/**/*.js', 'src/renderers/testing/**/*.js'],
|
||||
paths: [
|
||||
'src/renderers/shared/**/*.js',
|
||||
'src/renderers/testing/**/*.js',
|
||||
'src/shared/**/*.js',
|
||||
],
|
||||
},
|
||||
|
||||
/******* React Noop Renderer (used only for fixtures/fiber-debugger) *******/
|
||||
|
||||
@@ -24,7 +24,7 @@ var REACT_ELEMENT_TYPE =
|
||||
0xeac7;
|
||||
|
||||
if (__DEV__) {
|
||||
var {getCurrentStackAddendum} = require('ReactComponentTreeHook');
|
||||
var {getStackAddendum} = require('ReactDebugCurrentFrame');
|
||||
}
|
||||
|
||||
var SEPARATOR = '.';
|
||||
@@ -171,7 +171,7 @@ function traverseAllChildrenImpl(
|
||||
'Using Maps as children is unsupported and will likely yield ' +
|
||||
'unexpected results. Convert it to a sequence/iterable of keyed ' +
|
||||
'ReactElements instead.%s',
|
||||
getCurrentStackAddendum(),
|
||||
getStackAddendum(),
|
||||
);
|
||||
didWarnAboutMaps = true;
|
||||
}
|
||||
@@ -196,7 +196,7 @@ function traverseAllChildrenImpl(
|
||||
addendum =
|
||||
' If you meant to render a collection of children, use an array ' +
|
||||
'instead.' +
|
||||
getCurrentStackAddendum();
|
||||
getStackAddendum();
|
||||
}
|
||||
var childrenString = '' + children;
|
||||
invariant(
|
||||
|
||||
@@ -12,46 +12,18 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {Fiber} from 'ReactFiber';
|
||||
import type {DebugID} from 'ReactInstanceType';
|
||||
|
||||
const ReactDebugCurrentFrame = {};
|
||||
|
||||
if (__DEV__) {
|
||||
var {
|
||||
getStackAddendumByID,
|
||||
getCurrentStackAddendum,
|
||||
} = require('ReactComponentTreeHook');
|
||||
var {
|
||||
getStackAddendumByWorkInProgressFiber,
|
||||
} = require('ReactFiberComponentTreeHook');
|
||||
|
||||
// Component that is being worked on
|
||||
ReactDebugCurrentFrame.current = (null: Fiber | DebugID | null);
|
||||
|
||||
// Element that is being cloned or created
|
||||
ReactDebugCurrentFrame.element = (null: *);
|
||||
ReactDebugCurrentFrame.getCurrentStack = (null: null | (() => string | null));
|
||||
|
||||
ReactDebugCurrentFrame.getStackAddendum = function(): string | null {
|
||||
let stack = null;
|
||||
const current = ReactDebugCurrentFrame.current;
|
||||
const element = ReactDebugCurrentFrame.element;
|
||||
if (current !== null) {
|
||||
if (typeof current === 'number') {
|
||||
// DebugID from Stack.
|
||||
const debugID = current;
|
||||
stack = getStackAddendumByID(debugID);
|
||||
} else if (typeof current.tag === 'number') {
|
||||
// This is a Fiber.
|
||||
// The stack will only be correct if this is a work in progress
|
||||
// version and we're calling it during reconciliation.
|
||||
const workInProgress = current;
|
||||
stack = getStackAddendumByWorkInProgressFiber(workInProgress);
|
||||
}
|
||||
} else if (element !== null) {
|
||||
stack = getCurrentStackAddendum(element);
|
||||
const impl = ReactDebugCurrentFrame.getCurrentStack;
|
||||
if (impl) {
|
||||
return impl();
|
||||
}
|
||||
return stack;
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -21,14 +21,42 @@
|
||||
var ReactCurrentOwner = require('ReactCurrentOwner');
|
||||
var ReactElement = require('ReactElement');
|
||||
|
||||
var getComponentName = require('getComponentName');
|
||||
|
||||
if (__DEV__) {
|
||||
var checkPropTypes = require('prop-types/checkPropTypes');
|
||||
var lowPriorityWarning = require('lowPriorityWarning');
|
||||
var ReactDebugCurrentFrame = require('ReactDebugCurrentFrame');
|
||||
var warning = require('fbjs/lib/warning');
|
||||
var {getCurrentStackAddendum} = require('ReactComponentTreeHook');
|
||||
var describeComponentFrame = require('describeComponentFrame');
|
||||
var getComponentName = require('getComponentName');
|
||||
|
||||
var currentlyValidatingElement = null;
|
||||
|
||||
var getDisplayName = function(element: ?ReactElement): string {
|
||||
if (element == null) {
|
||||
return '#empty';
|
||||
} else if (typeof element === 'string' || typeof element === 'number') {
|
||||
return '#text';
|
||||
} else if (typeof element.type === 'string') {
|
||||
return element.type;
|
||||
} else {
|
||||
return element.type.displayName || element.type.name || 'Unknown';
|
||||
}
|
||||
};
|
||||
|
||||
var getStackAddendum = function(): string {
|
||||
var stack = '';
|
||||
if (currentlyValidatingElement) {
|
||||
var name = getDisplayName(currentlyValidatingElement);
|
||||
var owner = currentlyValidatingElement._owner;
|
||||
stack += describeComponentFrame(
|
||||
name,
|
||||
currentlyValidatingElement._source,
|
||||
owner && getComponentName(owner),
|
||||
);
|
||||
}
|
||||
stack += ReactDebugCurrentFrame.getStackAddendum() || '';
|
||||
return stack;
|
||||
};
|
||||
}
|
||||
|
||||
var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
|
||||
@@ -115,14 +143,16 @@ function validateExplicitKey(element, parentType) {
|
||||
childOwner = ` It was passed a child from ${getComponentName(element._owner)}.`;
|
||||
}
|
||||
|
||||
currentlyValidatingElement = element;
|
||||
warning(
|
||||
false,
|
||||
'Each child in an array or iterator should have a unique "key" prop.' +
|
||||
'%s%s See https://fb.me/react-warning-keys for more information.%s',
|
||||
currentComponentErrorInfo,
|
||||
childOwner,
|
||||
getCurrentStackAddendum(element),
|
||||
getStackAddendum(),
|
||||
);
|
||||
currentlyValidatingElement = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,13 +223,9 @@ function validatePropTypes(element) {
|
||||
: componentClass.propTypes;
|
||||
|
||||
if (propTypes) {
|
||||
checkPropTypes(
|
||||
propTypes,
|
||||
element.props,
|
||||
'prop',
|
||||
name,
|
||||
ReactDebugCurrentFrame.getStackAddendum,
|
||||
);
|
||||
currentlyValidatingElement = element;
|
||||
checkPropTypes(propTypes, element.props, 'prop', name, getStackAddendum);
|
||||
currentlyValidatingElement = null;
|
||||
}
|
||||
if (typeof componentClass.getDefaultProps === 'function') {
|
||||
warning(
|
||||
@@ -235,7 +261,7 @@ var ReactElementValidator = {
|
||||
info += getDeclarationErrorAddendum();
|
||||
}
|
||||
|
||||
info += getCurrentStackAddendum();
|
||||
info += ReactDebugCurrentFrame.getStackAddendum() || '';
|
||||
|
||||
warning(
|
||||
false,
|
||||
@@ -255,10 +281,6 @@ var ReactElementValidator = {
|
||||
return element;
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFrame.element = element;
|
||||
}
|
||||
|
||||
// Skip key warning if the type isn't valid since our key validation logic
|
||||
// doesn't expect a non-string/function type and can throw confusing errors.
|
||||
// We don't want exception behavior to differ between dev and prod.
|
||||
@@ -272,10 +294,6 @@ var ReactElementValidator = {
|
||||
|
||||
validatePropTypes(element);
|
||||
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFrame.element = null;
|
||||
}
|
||||
|
||||
return element;
|
||||
},
|
||||
|
||||
@@ -306,16 +324,10 @@ var ReactElementValidator = {
|
||||
|
||||
cloneElement: function(element, props, children) {
|
||||
var newElement = ReactElement.cloneElement.apply(this, arguments);
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFrame.element = newElement;
|
||||
}
|
||||
for (var i = 2; i < arguments.length; i++) {
|
||||
validateChildKeys(arguments[i], newElement.type);
|
||||
}
|
||||
validatePropTypes(newElement);
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFrame.element = null;
|
||||
}
|
||||
return newElement;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -13,17 +13,12 @@
|
||||
'use strict';
|
||||
|
||||
var ReactCurrentOwner = require('ReactCurrentOwner');
|
||||
var {
|
||||
getStackAddendumByWorkInProgressFiber,
|
||||
describeComponentFrame,
|
||||
} = require('ReactFiberComponentTreeHook');
|
||||
var invariant = require('fbjs/lib/invariant');
|
||||
var warning = require('fbjs/lib/warning');
|
||||
var getComponentName = require('getComponentName');
|
||||
var describeComponentFrame = require('describeComponentFrame');
|
||||
|
||||
import type {ReactElement, Source} from 'ReactElementType';
|
||||
import type {DebugID} from 'ReactInstanceType';
|
||||
import type {Fiber} from 'ReactFiber';
|
||||
|
||||
function isNative(fn) {
|
||||
// Based on isNative() from Lodash
|
||||
@@ -313,26 +308,15 @@ var ReactComponentTreeHook = {
|
||||
return item ? item.isMounted : false;
|
||||
},
|
||||
|
||||
getCurrentStackAddendum(topElement: ?ReactElement): string {
|
||||
getCurrentStackAddendum(): string {
|
||||
var info = '';
|
||||
if (topElement) {
|
||||
var name = getDisplayName(topElement);
|
||||
var owner = topElement._owner;
|
||||
info += describeComponentFrame(
|
||||
name,
|
||||
topElement._source,
|
||||
owner && getComponentName(owner),
|
||||
);
|
||||
}
|
||||
|
||||
var currentOwner = ReactCurrentOwner.current;
|
||||
if (currentOwner) {
|
||||
if (typeof currentOwner.tag === 'number') {
|
||||
const workInProgress = ((currentOwner: any): Fiber);
|
||||
// Safe because if current owner exists, we are reconciling,
|
||||
// and it is guaranteed to be the work-in-progress version.
|
||||
info += getStackAddendumByWorkInProgressFiber(workInProgress);
|
||||
} else if (typeof currentOwner._debugID === 'number') {
|
||||
invariant(
|
||||
typeof currentOwner.tag !== 'number',
|
||||
'Fiber owners should not show up in Stack stack traces.',
|
||||
);
|
||||
if (typeof currentOwner._debugID === 'number') {
|
||||
info += ReactComponentTreeHook.getStackAddendumByID(
|
||||
currentOwner._debugID,
|
||||
);
|
||||
|
||||
@@ -20,6 +20,7 @@ describe('ReactComponentTreeHook', () => {
|
||||
var ReactDOMServer;
|
||||
var ReactInstanceMap;
|
||||
var ReactComponentTreeHook;
|
||||
var ReactDebugCurrentFiber;
|
||||
var ReactComponentTreeTestUtils;
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -29,6 +30,7 @@ describe('ReactComponentTreeHook', () => {
|
||||
ReactDOM = require('react-dom');
|
||||
ReactDOMServer = require('react-dom/server');
|
||||
ReactInstanceMap = require('ReactInstanceMap');
|
||||
ReactDebugCurrentFiber = require('ReactDebugCurrentFiber');
|
||||
ReactComponentTreeHook = require('ReactComponentTreeHook');
|
||||
ReactComponentTreeTestUtils = require('ReactComponentTreeTestUtils');
|
||||
});
|
||||
@@ -37,7 +39,9 @@ describe('ReactComponentTreeHook', () => {
|
||||
describe('stack addenda', () => {
|
||||
it('gets created', () => {
|
||||
function getAddendum(element) {
|
||||
var addendum = ReactComponentTreeHook.getCurrentStackAddendum(element);
|
||||
var addendum = ReactDOMFeatureFlags.useFiber
|
||||
? ReactDebugCurrentFiber.getCurrentFiberStackAddendum() || ''
|
||||
: ReactComponentTreeHook.getCurrentStackAddendum();
|
||||
return addendum.replace(/\(at .+?:\d+\)/g, '(at **)');
|
||||
}
|
||||
|
||||
@@ -47,23 +51,23 @@ describe('ReactComponentTreeHook', () => {
|
||||
Object.defineProperty(Anon, 'name', {
|
||||
value: null,
|
||||
});
|
||||
function Orange() {
|
||||
return null;
|
||||
}
|
||||
// function Orange() {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
expectDev(getAddendum()).toBe('');
|
||||
expectDev(getAddendum(<div />)).toBe('\n in div (at **)');
|
||||
expectDev(getAddendum(<Anon />)).toBe('\n in Unknown (at **)');
|
||||
expectDev(getAddendum(<Orange />)).toBe('\n in Orange (at **)');
|
||||
expectDev(getAddendum(React.createElement(Orange))).toBe(
|
||||
'\n in Orange',
|
||||
);
|
||||
// expectDev(getAddendum(<div />)).toBe('\n in div (at **)');
|
||||
// expectDev(getAddendum(<Anon />)).toBe('\n in Unknown (at **)');
|
||||
// expectDev(getAddendum(<Orange />)).toBe('\n in Orange (at **)');
|
||||
// expectDev(getAddendum(React.createElement(Orange))).toBe(
|
||||
// '\n in Orange',
|
||||
// );
|
||||
|
||||
var renders = 0;
|
||||
var rOwnedByQ;
|
||||
//var rOwnedByQ;
|
||||
|
||||
function Q() {
|
||||
return (rOwnedByQ = React.createElement(R));
|
||||
return /*rOwnedByQ =*/ React.createElement(R);
|
||||
}
|
||||
function R() {
|
||||
return <div><S /></div>;
|
||||
@@ -82,15 +86,15 @@ describe('ReactComponentTreeHook', () => {
|
||||
'\n in Q (at **)',
|
||||
);
|
||||
expectDev(getAddendum(<span />)).toBe(
|
||||
'\n in span (at **)' +
|
||||
'\n in S (at **)' +
|
||||
// '\n in span (at **)' +
|
||||
'\n in S (at **)' +
|
||||
'\n in div (at **)' +
|
||||
'\n in R (created by Q)' +
|
||||
'\n in Q (at **)',
|
||||
);
|
||||
expectDev(getAddendum(React.createElement('span'))).toBe(
|
||||
'\n in span (created by S)' +
|
||||
'\n in S (at **)' +
|
||||
// '\n in span (created by S)' +
|
||||
'\n in S (at **)' +
|
||||
'\n in div (at **)' +
|
||||
'\n in R (created by Q)' +
|
||||
'\n in Q (at **)',
|
||||
@@ -103,7 +107,7 @@ describe('ReactComponentTreeHook', () => {
|
||||
expectDev(renders).toBe(2);
|
||||
|
||||
// Make sure owner is fetched for the top element too.
|
||||
expectDev(getAddendum(rOwnedByQ)).toBe('\n in R (created by Q)');
|
||||
// expectDev(getAddendum(rOwnedByQ)).toBe('\n in R (created by Q)');
|
||||
});
|
||||
|
||||
// These are features and regression tests that only affect
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
'use strict';
|
||||
|
||||
var DOMProperty = require('DOMProperty');
|
||||
var ReactDebugCurrentFiber = require('ReactDebugCurrentFiber');
|
||||
|
||||
var warning = require('fbjs/lib/warning');
|
||||
|
||||
@@ -20,7 +19,10 @@ var warnedProperties = {};
|
||||
var rARIA = new RegExp('^(aria)-[' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$');
|
||||
|
||||
if (__DEV__) {
|
||||
var {ReactComponentTreeHook} = require('ReactGlobalSharedState');
|
||||
var {
|
||||
ReactComponentTreeHook,
|
||||
ReactDebugCurrentFrame,
|
||||
} = require('ReactGlobalSharedState');
|
||||
var {getStackAddendumByID} = ReactComponentTreeHook;
|
||||
}
|
||||
|
||||
@@ -29,8 +31,9 @@ function getStackAddendum(debugID) {
|
||||
// This can only happen on Stack
|
||||
return getStackAddendumByID(debugID);
|
||||
} else {
|
||||
// This can only happen on Fiber
|
||||
return ReactDebugCurrentFiber.getCurrentFiberStackAddendum();
|
||||
// This can only happen on Fiber / Server
|
||||
var stack = ReactDebugCurrentFrame.getStackAddendum();
|
||||
return stack != null ? stack : '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,11 +11,13 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var ReactDebugCurrentFiber = require('ReactDebugCurrentFiber');
|
||||
var warning = require('fbjs/lib/warning');
|
||||
|
||||
if (__DEV__) {
|
||||
var {ReactComponentTreeHook} = require('ReactGlobalSharedState');
|
||||
var {
|
||||
ReactComponentTreeHook,
|
||||
ReactDebugCurrentFrame,
|
||||
} = require('ReactGlobalSharedState');
|
||||
var {getStackAddendumByID} = ReactComponentTreeHook;
|
||||
}
|
||||
|
||||
@@ -26,8 +28,9 @@ function getStackAddendum(debugID) {
|
||||
// This can only happen on Stack
|
||||
return getStackAddendumByID(debugID);
|
||||
} else {
|
||||
// This can only happen on Fiber
|
||||
return ReactDebugCurrentFiber.getCurrentFiberStackAddendum();
|
||||
// This can only happen on Fiber / Server
|
||||
var stack = ReactDebugCurrentFrame.getStackAddendum();
|
||||
return stack != null ? stack : '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,18 +13,24 @@
|
||||
|
||||
var DOMProperty = require('DOMProperty');
|
||||
var EventPluginRegistry = require('EventPluginRegistry');
|
||||
var ReactDebugCurrentFiber = require('ReactDebugCurrentFiber');
|
||||
var {ReactComponentTreeHook} = require('ReactGlobalSharedState');
|
||||
|
||||
var warning = require('fbjs/lib/warning');
|
||||
|
||||
if (__DEV__) {
|
||||
var {
|
||||
ReactComponentTreeHook,
|
||||
ReactDebugCurrentFrame,
|
||||
} = require('ReactGlobalSharedState');
|
||||
var {getStackAddendumByID} = ReactComponentTreeHook;
|
||||
}
|
||||
|
||||
function getStackAddendum(debugID) {
|
||||
if (debugID != null) {
|
||||
// This can only happen on Stack
|
||||
return ReactComponentTreeHook.getStackAddendumByID(debugID);
|
||||
return getStackAddendumByID(debugID);
|
||||
} else {
|
||||
// This can only happen on Fiber / Server
|
||||
var stack = ReactDebugCurrentFiber.getCurrentFiberStackAddendum();
|
||||
var stack = ReactDebugCurrentFrame.getStackAddendum();
|
||||
return stack != null ? stack : '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ import type {Fiber} from 'ReactFiber';
|
||||
|
||||
type LifeCyclePhase = 'render' | 'getChildContext';
|
||||
|
||||
var {ReactDebugCurrentFrame} = require('ReactGlobalSharedState');
|
||||
|
||||
if (__DEV__) {
|
||||
var getComponentName = require('getComponentName');
|
||||
var {
|
||||
@@ -49,10 +51,23 @@ function getCurrentFiberStackAddendum(): string | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
function resetCurrentFiber() {
|
||||
ReactDebugCurrentFrame.getCurrentStack = null;
|
||||
ReactDebugCurrentFiber.current = null;
|
||||
ReactDebugCurrentFiber.phase = null;
|
||||
}
|
||||
|
||||
function setCurrentFiber(fiber: Fiber | null, phase: LifeCyclePhase | null) {
|
||||
ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackAddendum;
|
||||
ReactDebugCurrentFiber.current = fiber;
|
||||
ReactDebugCurrentFiber.phase = phase;
|
||||
}
|
||||
|
||||
var ReactDebugCurrentFiber = {
|
||||
current: (null: Fiber | null),
|
||||
phase: (null: LifeCyclePhase | null),
|
||||
|
||||
resetCurrentFiber,
|
||||
setCurrentFiber,
|
||||
getCurrentFiberOwnerName,
|
||||
getCurrentFiberStackAddendum,
|
||||
};
|
||||
|
||||
@@ -217,9 +217,9 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||
|
||||
if (__DEV__) {
|
||||
ReactCurrentOwner.current = workInProgress;
|
||||
ReactDebugCurrentFiber.phase = 'render';
|
||||
ReactDebugCurrentFiber.setCurrentFiber(workInProgress, 'render');
|
||||
nextChildren = fn(nextProps, context);
|
||||
ReactDebugCurrentFiber.phase = null;
|
||||
ReactDebugCurrentFiber.setCurrentFiber(workInProgress, null);
|
||||
} else {
|
||||
nextChildren = fn(nextProps, context);
|
||||
}
|
||||
@@ -286,9 +286,9 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||
ReactCurrentOwner.current = workInProgress;
|
||||
let nextChildren;
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFiber.phase = 'render';
|
||||
ReactDebugCurrentFiber.setCurrentFiber(workInProgress, 'render');
|
||||
nextChildren = instance.render();
|
||||
ReactDebugCurrentFiber.phase = null;
|
||||
ReactDebugCurrentFiber.setCurrentFiber(workInProgress, null);
|
||||
} else {
|
||||
nextChildren = instance.render();
|
||||
}
|
||||
@@ -725,7 +725,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFiber.current = workInProgress;
|
||||
ReactDebugCurrentFiber.setCurrentFiber(workInProgress, null);
|
||||
}
|
||||
|
||||
switch (workInProgress.tag) {
|
||||
|
||||
@@ -187,7 +187,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||
renderPriority: PriorityLevel,
|
||||
): Fiber | null {
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFiber.current = workInProgress;
|
||||
ReactDebugCurrentFiber.setCurrentFiber(workInProgress, null);
|
||||
}
|
||||
|
||||
// Get the latest props.
|
||||
|
||||
@@ -26,7 +26,6 @@ const {createCursor, pop, push} = require('ReactFiberStack');
|
||||
|
||||
if (__DEV__) {
|
||||
var ReactDebugCurrentFiber = require('ReactDebugCurrentFiber');
|
||||
var {ReactDebugCurrentFrame} = require('ReactGlobalSharedState');
|
||||
var {startPhaseTimer, stopPhaseTimer} = require('ReactDebugFiberPerf');
|
||||
var warnedAboutMissingGetChildContext = {};
|
||||
}
|
||||
@@ -92,15 +91,15 @@ exports.getMaskedContext = function(
|
||||
|
||||
if (__DEV__) {
|
||||
const name = getComponentName(workInProgress) || 'Unknown';
|
||||
ReactDebugCurrentFrame.current = workInProgress;
|
||||
ReactDebugCurrentFiber.setCurrentFiber(workInProgress, null);
|
||||
checkPropTypes(
|
||||
contextTypes,
|
||||
context,
|
||||
'context',
|
||||
name,
|
||||
ReactDebugCurrentFrame.getStackAddendum,
|
||||
ReactDebugCurrentFiber.getCurrentFiberStackAddendum,
|
||||
);
|
||||
ReactDebugCurrentFrame.current = null;
|
||||
ReactDebugCurrentFiber.resetCurrentFiber();
|
||||
}
|
||||
|
||||
// Cache unmasked context so we can avoid recreating masked context unless necessary.
|
||||
@@ -181,11 +180,11 @@ function processChildContext(
|
||||
|
||||
let childContext;
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFiber.phase = 'getChildContext';
|
||||
ReactDebugCurrentFiber.setCurrentFiber(fiber, 'getChildContext');
|
||||
startPhaseTimer(fiber, 'getChildContext');
|
||||
childContext = instance.getChildContext();
|
||||
stopPhaseTimer();
|
||||
ReactDebugCurrentFiber.phase = null;
|
||||
ReactDebugCurrentFiber.resetCurrentFiber();
|
||||
} else {
|
||||
childContext = instance.getChildContext();
|
||||
}
|
||||
@@ -205,15 +204,15 @@ function processChildContext(
|
||||
// assume anything about the given fiber. We won't pass it down if we aren't sure.
|
||||
// TODO: remove this hack when we delete unstable_renderSubtree in Fiber.
|
||||
const workInProgress = isReconciling ? fiber : null;
|
||||
ReactDebugCurrentFrame.current = workInProgress;
|
||||
ReactDebugCurrentFiber.setCurrentFiber(workInProgress, null);
|
||||
checkPropTypes(
|
||||
childContextTypes,
|
||||
childContext,
|
||||
'child context',
|
||||
name,
|
||||
ReactDebugCurrentFrame.getStackAddendum,
|
||||
ReactDebugCurrentFiber.getCurrentFiberStackAddendum,
|
||||
);
|
||||
ReactDebugCurrentFrame.current = null;
|
||||
ReactDebugCurrentFiber.resetCurrentFiber();
|
||||
}
|
||||
|
||||
return {...parentContext, ...childContext};
|
||||
|
||||
@@ -322,7 +322,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||
function commitAllHostEffects() {
|
||||
while (nextEffect !== null) {
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFiber.current = nextEffect;
|
||||
ReactDebugCurrentFiber.setCurrentFiber(nextEffect, null);
|
||||
recordEffect();
|
||||
}
|
||||
|
||||
@@ -383,7 +383,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFiber.current = null;
|
||||
ReactDebugCurrentFiber.resetCurrentFiber();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -711,7 +711,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||
|
||||
ReactCurrentOwner.current = null;
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFiber.current = null;
|
||||
ReactDebugCurrentFiber.resetCurrentFiber();
|
||||
}
|
||||
|
||||
return next;
|
||||
@@ -740,7 +740,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||
|
||||
ReactCurrentOwner.current = null;
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFiber.current = null;
|
||||
ReactDebugCurrentFiber.resetCurrentFiber();
|
||||
}
|
||||
|
||||
return next;
|
||||
@@ -1024,8 +1024,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||
// It is no longer valid because we exited the user code.
|
||||
ReactCurrentOwner.current = null;
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFiber.current = null;
|
||||
ReactDebugCurrentFiber.phase = null;
|
||||
ReactDebugCurrentFiber.resetCurrentFiber();
|
||||
}
|
||||
// It is no longer valid because this unit of work failed.
|
||||
nextUnitOfWork = null;
|
||||
|
||||
@@ -42,6 +42,49 @@ if (__DEV__) {
|
||||
validateInputPropertes(type, props);
|
||||
validateUnknownPropertes(type, props);
|
||||
};
|
||||
|
||||
var describeComponentFrame = require('describeComponentFrame');
|
||||
var describeStackFrame = function(
|
||||
frame: {
|
||||
tag?: string,
|
||||
children: Array<*>,
|
||||
childIndex: number,
|
||||
},
|
||||
): string {
|
||||
var element = frame.children[frame.childIndex - 1];
|
||||
if (!element) {
|
||||
return '';
|
||||
}
|
||||
var source = element._source;
|
||||
var type = element.type;
|
||||
var name = typeof type === 'string'
|
||||
? type
|
||||
: typeof type === 'function' ? type.displayName || type.name : null;
|
||||
var ownerName = null;
|
||||
return describeComponentFrame(name, source, ownerName);
|
||||
};
|
||||
|
||||
var {ReactDebugCurrentFrame} = require('ReactGlobalSharedState');
|
||||
var currentDebugStack = null;
|
||||
var setCurrentDebugStack = function(stack) {
|
||||
currentDebugStack = stack;
|
||||
ReactDebugCurrentFrame.getCurrentStack = getStackAddendum;
|
||||
};
|
||||
var resetCurrentDebugStack = function() {
|
||||
currentDebugStack = null;
|
||||
ReactDebugCurrentFrame.getCurrentStack = null;
|
||||
};
|
||||
var getStackAddendum = function(): null | string {
|
||||
if (currentDebugStack === null) {
|
||||
return null;
|
||||
}
|
||||
let stack = '';
|
||||
let debugStack = currentDebugStack;
|
||||
for (let i = debugStack.length - 1; i >= 0; i--) {
|
||||
stack += describeStackFrame(debugStack[i]);
|
||||
}
|
||||
return stack;
|
||||
};
|
||||
}
|
||||
|
||||
var didWarnDefaultInputValue = false;
|
||||
@@ -145,13 +188,7 @@ function maskContext(type, context) {
|
||||
|
||||
function checkContextTypes(typeSpecs, values, location: string) {
|
||||
if (__DEV__) {
|
||||
checkPropTypes(
|
||||
typeSpecs,
|
||||
values,
|
||||
location,
|
||||
'Component',
|
||||
() => '', // ReactDebugCurrentFrame.getStackAddendum,
|
||||
);
|
||||
checkPropTypes(typeSpecs, values, location, 'Component', getStackAddendum);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,7 +411,13 @@ class ReactDOMServerRenderer {
|
||||
continue;
|
||||
}
|
||||
var child = frame.children[frame.childIndex++];
|
||||
if (__DEV__) {
|
||||
setCurrentDebugStack(this.stack);
|
||||
}
|
||||
out += this.render(child, frame.context);
|
||||
if (__DEV__) {
|
||||
resetCurrentDebugStack();
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ var {ReactCurrentOwner} = require('ReactGlobalSharedState');
|
||||
|
||||
if (__DEV__) {
|
||||
var {ReactDebugCurrentFrame} = require('ReactGlobalSharedState');
|
||||
var ReactDebugCurrentStack = require('ReactDebugCurrentStack');
|
||||
var warningAboutMissingGetChildContext = {};
|
||||
}
|
||||
|
||||
@@ -403,6 +404,8 @@ var ReactCompositeComponent = {
|
||||
) {
|
||||
if (__DEV__) {
|
||||
ReactCurrentOwner.current = this;
|
||||
ReactDebugCurrentFrame.getCurrentStack =
|
||||
ReactDebugCurrentStack.getStackAddendum;
|
||||
try {
|
||||
return this._constructComponentWithoutOwner(
|
||||
doConstruct,
|
||||
@@ -412,6 +415,7 @@ var ReactCompositeComponent = {
|
||||
);
|
||||
} finally {
|
||||
ReactCurrentOwner.current = null;
|
||||
ReactDebugCurrentFrame.getCurrentStack = null;
|
||||
}
|
||||
} else {
|
||||
return this._constructComponentWithoutOwner(
|
||||
@@ -746,15 +750,15 @@ var ReactCompositeComponent = {
|
||||
*/
|
||||
_checkContextTypes: function(typeSpecs, values, location: string) {
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFrame.current = this._debugID;
|
||||
ReactDebugCurrentStack.current = this._debugID;
|
||||
checkPropTypes(
|
||||
typeSpecs,
|
||||
values,
|
||||
location,
|
||||
this.getName(),
|
||||
ReactDebugCurrentFrame.getStackAddendum,
|
||||
ReactDebugCurrentStack.getStackAddendum,
|
||||
);
|
||||
ReactDebugCurrentFrame.current = null;
|
||||
ReactDebugCurrentStack.current = null;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1246,10 +1250,17 @@ var ReactCompositeComponent = {
|
||||
this._compositeType !== ReactCompositeComponentTypes.StatelessFunctional
|
||||
) {
|
||||
ReactCurrentOwner.current = this;
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFrame.getCurrentStack =
|
||||
ReactDebugCurrentStack.getStackAddendum;
|
||||
}
|
||||
try {
|
||||
renderedElement = this._renderValidatedComponentWithoutOwnerOrContext();
|
||||
} finally {
|
||||
ReactCurrentOwner.current = null;
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFrame.getCurrentStack = null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
renderedElement = this._renderValidatedComponentWithoutOwnerOrContext();
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright 2013-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 ReactDebugCurrentStack
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {DebugID} from 'ReactInstanceType';
|
||||
|
||||
const ReactDebugCurrentStack = {};
|
||||
|
||||
if (__DEV__) {
|
||||
var {ReactComponentTreeHook} = require('ReactGlobalSharedState');
|
||||
var {getStackAddendumByID, getCurrentStackAddendum} = ReactComponentTreeHook;
|
||||
|
||||
// Component that is being worked on
|
||||
ReactDebugCurrentStack.current = (null: DebugID | null);
|
||||
|
||||
ReactDebugCurrentStack.getStackAddendum = function(): string | null {
|
||||
let stack = null;
|
||||
const current = ReactDebugCurrentStack.current;
|
||||
if (current !== null) {
|
||||
stack = getStackAddendumByID(current);
|
||||
} else {
|
||||
stack = getCurrentStackAddendum();
|
||||
}
|
||||
return stack;
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = ReactDebugCurrentStack;
|
||||
@@ -18,6 +18,10 @@ var ReactInstrumentation = require('ReactInstrumentation');
|
||||
var ReactReconciler = require('ReactReconciler');
|
||||
var ReactChildReconciler = require('ReactChildReconciler');
|
||||
var {ReactCurrentOwner} = require('ReactGlobalSharedState');
|
||||
if (__DEV__) {
|
||||
var {ReactDebugCurrentFrame} = require('ReactGlobalSharedState');
|
||||
var ReactDebugCurrentStack = require('ReactDebugCurrentStack');
|
||||
}
|
||||
|
||||
var emptyFunction = require('fbjs/lib/emptyFunction');
|
||||
var flattenStackChildren = require('flattenStackChildren');
|
||||
@@ -179,6 +183,8 @@ var ReactMultiChild = {
|
||||
if (this._currentElement) {
|
||||
try {
|
||||
ReactCurrentOwner.current = this._currentElement._owner;
|
||||
ReactDebugCurrentFrame.getCurrentStack =
|
||||
ReactDebugCurrentStack.getStackAddendum;
|
||||
return ReactChildReconciler.instantiateChildren(
|
||||
nestedChildren,
|
||||
transaction,
|
||||
@@ -187,6 +193,7 @@ var ReactMultiChild = {
|
||||
);
|
||||
} finally {
|
||||
ReactCurrentOwner.current = null;
|
||||
ReactDebugCurrentFrame.getCurrentStack = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -212,12 +219,15 @@ var ReactMultiChild = {
|
||||
if (this._currentElement) {
|
||||
try {
|
||||
ReactCurrentOwner.current = this._currentElement._owner;
|
||||
ReactDebugCurrentFrame.getCurrentStack =
|
||||
ReactDebugCurrentStack.getStackAddendum;
|
||||
nextChildren = flattenStackChildren(
|
||||
nextNestedChildrenElements,
|
||||
selfDebugID,
|
||||
);
|
||||
} finally {
|
||||
ReactCurrentOwner.current = null;
|
||||
ReactDebugCurrentFrame.getCurrentStack = null;
|
||||
}
|
||||
ReactChildReconciler.updateChildren(
|
||||
prevChildren,
|
||||
|
||||
@@ -18,7 +18,38 @@ const React = require('react');
|
||||
const emptyObject = require('fbjs/lib/emptyObject');
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
|
||||
const {ReactDebugCurrentFrame} = require('ReactGlobalSharedState');
|
||||
if (__DEV__) {
|
||||
var describeComponentFrame = require('describeComponentFrame');
|
||||
var getComponentName = require('getComponentName');
|
||||
|
||||
var currentlyValidatingElement = null;
|
||||
|
||||
var getDisplayName = function(element: ?ReactElement): string {
|
||||
if (element == null) {
|
||||
return '#empty';
|
||||
} else if (typeof element === 'string' || typeof element === 'number') {
|
||||
return '#text';
|
||||
} else if (typeof element.type === 'string') {
|
||||
return element.type;
|
||||
} else {
|
||||
return element.type.displayName || element.type.name || 'Unknown';
|
||||
}
|
||||
};
|
||||
|
||||
var getStackAddendum = function(): string {
|
||||
var stack = '';
|
||||
if (currentlyValidatingElement) {
|
||||
var name = getDisplayName(currentlyValidatingElement);
|
||||
var owner = currentlyValidatingElement._owner;
|
||||
stack += describeComponentFrame(
|
||||
name,
|
||||
currentlyValidatingElement._source,
|
||||
owner && getComponentName(owner),
|
||||
);
|
||||
}
|
||||
return stack;
|
||||
};
|
||||
}
|
||||
|
||||
class ReactShallowRenderer {
|
||||
static createRenderer = function() {
|
||||
@@ -79,17 +110,17 @@ class ReactShallowRenderer {
|
||||
);
|
||||
|
||||
if (element.type.hasOwnProperty('contextTypes')) {
|
||||
ReactDebugCurrentFrame.element = element;
|
||||
currentlyValidatingElement = element;
|
||||
|
||||
checkPropTypes(
|
||||
element.type.contextTypes,
|
||||
context,
|
||||
'context',
|
||||
getName(element.type, this._instance),
|
||||
ReactDebugCurrentFrame.getStackAddendum,
|
||||
getStackAddendum,
|
||||
);
|
||||
|
||||
ReactDebugCurrentFrame.element = null;
|
||||
currentlyValidatingElement = null;
|
||||
}
|
||||
|
||||
this._mountClassComponent(element.props, context);
|
||||
|
||||
@@ -19,24 +19,11 @@ var {
|
||||
ClassComponent,
|
||||
HostComponent,
|
||||
} = ReactTypeOfWork;
|
||||
var describeComponentFrame = require('describeComponentFrame');
|
||||
var getComponentName = require('getComponentName');
|
||||
|
||||
import type {Fiber} from 'ReactFiber';
|
||||
|
||||
function describeComponentFrame(name, source: any, ownerName) {
|
||||
return (
|
||||
'\n in ' +
|
||||
(name || 'Unknown') +
|
||||
(source
|
||||
? ' (at ' +
|
||||
source.fileName.replace(/^.*[\\\/]/, '') +
|
||||
':' +
|
||||
source.lineNumber +
|
||||
')'
|
||||
: ownerName ? ' (created by ' + ownerName + ')' : '')
|
||||
);
|
||||
}
|
||||
|
||||
function describeFiber(fiber: Fiber): string {
|
||||
switch (fiber.tag) {
|
||||
case IndeterminateComponent:
|
||||
@@ -72,5 +59,4 @@ function getStackAddendumByWorkInProgressFiber(workInProgress: Fiber): string {
|
||||
|
||||
module.exports = {
|
||||
getStackAddendumByWorkInProgressFiber,
|
||||
describeComponentFrame,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright 2016-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.
|
||||
*
|
||||
* @flow
|
||||
* @providesModule describeComponentFrame
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = function(
|
||||
name: null | string,
|
||||
source: any,
|
||||
ownerName: null | string,
|
||||
) {
|
||||
return (
|
||||
'\n in ' +
|
||||
(name || 'Unknown') +
|
||||
(source
|
||||
? ' (at ' +
|
||||
source.fileName.replace(/^.*[\\\/]/, '') +
|
||||
':' +
|
||||
source.lineNumber +
|
||||
')'
|
||||
: ownerName ? ' (created by ' + ownerName + ')' : '')
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user