mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Refactor stack handling (no functional changes) (#13165)
* Refactor ReactDebugCurrentFiber to use named exports This makes the difference between it and ReactFiberCurrentFrame a bit clearer. ReactDebugCurrentFiber is Fiber's own implementation. ReactFiberCurrentFrame is the thing that holds a reference to the current implementation and delegates to it. * Unify ReactFiberComponentTreeHook and ReactDebugCurrentFiber Conceptually they're very related. ReactFiberComponentTreeHook contains implementation details of reading Fiber's stack (both in DEV and PROD). ReactDebugCurrentFiber contained a reference to the current fiber, and used the above utility. It was confusing when to use which one. Colocating them makes it clearer what you could do with each method. In the future, the plan is to stop using these methods explicitly in most places, and instead delegate to a warning system that includes stacks automatically. This change makes future refactorings simpler by colocating related logic. * Rename methods to better reflect their meanings Clarify which are DEV or PROD-only. Clarify which can return null. I believe the "work in progress only" was a mistake. I introduced it because I wasn't sure what guarantees we have around .return. But we know for sure that following a .return chain gives us an accurate stack even if we get into WIP trees because we don't have reparenting. So it's fine to relax that naming. * Rename ReactDebugCurrentFiber -> ReactCurrentFiber It's not completely DEV-only anymore. Individual methods already specify whether they work in DEV or PROD in their names.
This commit is contained in:
+23
-16
@@ -8,7 +8,10 @@
|
||||
*/
|
||||
|
||||
// TODO: direct imports like some-package/src/* are bad. Fix me.
|
||||
import ReactDebugCurrentFiber from 'react-reconciler/src/ReactDebugCurrentFiber';
|
||||
import {
|
||||
getCurrentFiberOwnerNameInDevOrNull,
|
||||
getCurrentFiberStackInDevOrNull,
|
||||
} from 'react-reconciler/src/ReactCurrentFiber';
|
||||
import {registrationNameModules} from 'events/EventPluginRegistry';
|
||||
import warning from 'shared/warning';
|
||||
|
||||
@@ -45,10 +48,6 @@ import {validateProperties as validateARIAProperties} from '../shared/ReactDOMIn
|
||||
import {validateProperties as validateInputProperties} from '../shared/ReactDOMNullInputValuePropHook';
|
||||
import {validateProperties as validateUnknownProperties} from '../shared/ReactDOMUnknownPropertyHook';
|
||||
|
||||
const {
|
||||
getCurrentFiberOwnerName,
|
||||
getCurrentFiberStackAddendum,
|
||||
} = ReactDebugCurrentFiber;
|
||||
let didWarnInvalidHydration = false;
|
||||
let didWarnShadyDOM = false;
|
||||
|
||||
@@ -62,7 +61,7 @@ const HTML = '__html';
|
||||
|
||||
const {html: HTML_NAMESPACE} = Namespaces;
|
||||
|
||||
let getStack = () => '';
|
||||
let getStackInDevOrNull = () => '';
|
||||
|
||||
let warnedUnknownTags;
|
||||
let suppressHydrationWarning;
|
||||
@@ -77,7 +76,7 @@ let normalizeMarkupForTextOrAttribute;
|
||||
let normalizeHTML;
|
||||
|
||||
if (__DEV__) {
|
||||
getStack = getCurrentFiberStackAddendum;
|
||||
getStackInDevOrNull = getCurrentFiberStackInDevOrNull;
|
||||
|
||||
warnedUnknownTags = {
|
||||
// Chrome is the only major browser not shipping <time>. But as of July
|
||||
@@ -181,7 +180,7 @@ if (__DEV__) {
|
||||
registrationName,
|
||||
registrationName,
|
||||
registrationName,
|
||||
getCurrentFiberStackAddendum(),
|
||||
getCurrentFiberStackInDevOrNull(),
|
||||
);
|
||||
} else {
|
||||
warning(
|
||||
@@ -189,7 +188,7 @@ if (__DEV__) {
|
||||
'Expected `%s` listener to be a function, instead got a value of `%s` type.%s',
|
||||
registrationName,
|
||||
typeof listener,
|
||||
getCurrentFiberStackAddendum(),
|
||||
getCurrentFiberStackInDevOrNull(),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -267,7 +266,11 @@ function setInitialDOMProperties(
|
||||
}
|
||||
}
|
||||
// Relies on `updateStylesByID` not mutating `styleUpdates`.
|
||||
CSSPropertyOperations.setValueForStyles(domElement, nextProp, getStack);
|
||||
CSSPropertyOperations.setValueForStyles(
|
||||
domElement,
|
||||
nextProp,
|
||||
getStackInDevOrNull,
|
||||
);
|
||||
} else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
|
||||
const nextHtml = nextProp ? nextProp[HTML] : undefined;
|
||||
if (nextHtml != null) {
|
||||
@@ -323,7 +326,11 @@ function updateDOMProperties(
|
||||
const propKey = updatePayload[i];
|
||||
const propValue = updatePayload[i + 1];
|
||||
if (propKey === STYLE) {
|
||||
CSSPropertyOperations.setValueForStyles(domElement, propValue, getStack);
|
||||
CSSPropertyOperations.setValueForStyles(
|
||||
domElement,
|
||||
propValue,
|
||||
getStackInDevOrNull,
|
||||
);
|
||||
} else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
|
||||
setInnerHTML(domElement, propValue);
|
||||
} else if (propKey === CHILDREN) {
|
||||
@@ -442,7 +449,7 @@ export function setInitialProperties(
|
||||
false,
|
||||
'%s is using shady DOM. Using shady DOM with React can ' +
|
||||
'cause things to break subtly.',
|
||||
getCurrentFiberOwnerName() || 'A component',
|
||||
getCurrentFiberOwnerNameInDevOrNull() || 'A component',
|
||||
);
|
||||
didWarnShadyDOM = true;
|
||||
}
|
||||
@@ -516,7 +523,7 @@ export function setInitialProperties(
|
||||
props = rawProps;
|
||||
}
|
||||
|
||||
assertValidProps(tag, props, getStack);
|
||||
assertValidProps(tag, props, getStackInDevOrNull);
|
||||
|
||||
setInitialDOMProperties(
|
||||
tag,
|
||||
@@ -604,7 +611,7 @@ export function diffProperties(
|
||||
break;
|
||||
}
|
||||
|
||||
assertValidProps(tag, nextProps, getStack);
|
||||
assertValidProps(tag, nextProps, getStackInDevOrNull);
|
||||
|
||||
let propKey;
|
||||
let styleName;
|
||||
@@ -834,7 +841,7 @@ export function diffHydratedProperties(
|
||||
false,
|
||||
'%s is using shady DOM. Using shady DOM with React can ' +
|
||||
'cause things to break subtly.',
|
||||
getCurrentFiberOwnerName() || 'A component',
|
||||
getCurrentFiberOwnerNameInDevOrNull() || 'A component',
|
||||
);
|
||||
didWarnShadyDOM = true;
|
||||
}
|
||||
@@ -895,7 +902,7 @@ export function diffHydratedProperties(
|
||||
break;
|
||||
}
|
||||
|
||||
assertValidProps(tag, rawProps, getStack);
|
||||
assertValidProps(tag, rawProps, getStackInDevOrNull);
|
||||
|
||||
if (__DEV__) {
|
||||
extraAttributeNames = new Set();
|
||||
|
||||
+9
-10
@@ -8,7 +8,10 @@
|
||||
*/
|
||||
|
||||
// TODO: direct imports like some-package/src/* are bad. Fix me.
|
||||
import ReactDebugCurrentFiber from 'react-reconciler/src/ReactDebugCurrentFiber';
|
||||
import {
|
||||
getCurrentFiberOwnerNameInDevOrNull,
|
||||
getCurrentFiberStackInDevOrNull,
|
||||
} from 'react-reconciler/src/ReactCurrentFiber';
|
||||
import invariant from 'shared/invariant';
|
||||
import warning from 'shared/warning';
|
||||
|
||||
@@ -25,10 +28,6 @@ type InputWithWrapperState = HTMLInputElement & {
|
||||
},
|
||||
};
|
||||
|
||||
const {
|
||||
getCurrentFiberOwnerName,
|
||||
getCurrentFiberStackAddendum,
|
||||
} = ReactDebugCurrentFiber;
|
||||
let didWarnValueDefaultValue = false;
|
||||
let didWarnCheckedDefaultChecked = false;
|
||||
let didWarnControlledToUncontrolled = false;
|
||||
@@ -75,7 +74,7 @@ export function initWrapperState(element: Element, props: Object) {
|
||||
ReactControlledValuePropTypes.checkPropTypes(
|
||||
'input',
|
||||
props,
|
||||
getCurrentFiberStackAddendum,
|
||||
getCurrentFiberStackInDevOrNull,
|
||||
);
|
||||
|
||||
if (
|
||||
@@ -91,7 +90,7 @@ export function initWrapperState(element: Element, props: Object) {
|
||||
'both). Decide between using a controlled or uncontrolled input ' +
|
||||
'element and remove one of these props. More info: ' +
|
||||
'https://fb.me/react-controlled-components',
|
||||
getCurrentFiberOwnerName() || 'A component',
|
||||
getCurrentFiberOwnerNameInDevOrNull() || 'A component',
|
||||
props.type,
|
||||
);
|
||||
didWarnCheckedDefaultChecked = true;
|
||||
@@ -109,7 +108,7 @@ export function initWrapperState(element: Element, props: Object) {
|
||||
'both). Decide between using a controlled or uncontrolled input ' +
|
||||
'element and remove one of these props. More info: ' +
|
||||
'https://fb.me/react-controlled-components',
|
||||
getCurrentFiberOwnerName() || 'A component',
|
||||
getCurrentFiberOwnerNameInDevOrNull() || 'A component',
|
||||
props.type,
|
||||
);
|
||||
didWarnValueDefaultValue = true;
|
||||
@@ -154,7 +153,7 @@ export function updateWrapper(element: Element, props: Object) {
|
||||
'Decide between using a controlled or uncontrolled input ' +
|
||||
'element for the lifetime of the component. More info: https://fb.me/react-controlled-components%s',
|
||||
props.type,
|
||||
getCurrentFiberStackAddendum(),
|
||||
getCurrentFiberStackInDevOrNull(),
|
||||
);
|
||||
didWarnUncontrolledToControlled = true;
|
||||
}
|
||||
@@ -170,7 +169,7 @@ export function updateWrapper(element: Element, props: Object) {
|
||||
'Decide between using a controlled or uncontrolled input ' +
|
||||
'element for the lifetime of the component. More info: https://fb.me/react-controlled-components%s',
|
||||
props.type,
|
||||
getCurrentFiberStackAddendum(),
|
||||
getCurrentFiberStackInDevOrNull(),
|
||||
);
|
||||
didWarnControlledToUncontrolled = true;
|
||||
}
|
||||
|
||||
+6
-8
@@ -8,16 +8,14 @@
|
||||
*/
|
||||
|
||||
// TODO: direct imports like some-package/src/* are bad. Fix me.
|
||||
import ReactDebugCurrentFiber from 'react-reconciler/src/ReactDebugCurrentFiber';
|
||||
import {
|
||||
getCurrentFiberOwnerNameInDevOrNull,
|
||||
getCurrentFiberStackInDevOrNull,
|
||||
} from 'react-reconciler/src/ReactCurrentFiber';
|
||||
import warning from 'shared/warning';
|
||||
|
||||
import ReactControlledValuePropTypes from '../shared/ReactControlledValuePropTypes';
|
||||
|
||||
const {
|
||||
getCurrentFiberOwnerName,
|
||||
getCurrentFiberStackAddendum,
|
||||
} = ReactDebugCurrentFiber;
|
||||
|
||||
let didWarnValueDefaultValue;
|
||||
|
||||
if (__DEV__) {
|
||||
@@ -32,7 +30,7 @@ type SelectWithWrapperState = HTMLSelectElement & {
|
||||
};
|
||||
|
||||
function getDeclarationErrorAddendum() {
|
||||
const ownerName = getCurrentFiberOwnerName();
|
||||
const ownerName = getCurrentFiberOwnerNameInDevOrNull();
|
||||
if (ownerName) {
|
||||
return '\n\nCheck the render method of `' + ownerName + '`.';
|
||||
}
|
||||
@@ -48,7 +46,7 @@ function checkSelectPropTypes(props) {
|
||||
ReactControlledValuePropTypes.checkPropTypes(
|
||||
'select',
|
||||
props,
|
||||
getCurrentFiberStackAddendum,
|
||||
getCurrentFiberStackInDevOrNull,
|
||||
);
|
||||
|
||||
for (let i = 0; i < valuePropNames.length; i++) {
|
||||
|
||||
+2
-3
@@ -10,11 +10,10 @@
|
||||
import invariant from 'shared/invariant';
|
||||
import warning from 'shared/warning';
|
||||
// TODO: direct imports like some-package/src/* are bad. Fix me.
|
||||
import ReactDebugCurrentFiber from 'react-reconciler/src/ReactDebugCurrentFiber';
|
||||
import {getCurrentFiberStackInDevOrNull} from 'react-reconciler/src/ReactCurrentFiber';
|
||||
|
||||
import ReactControlledValuePropTypes from '../shared/ReactControlledValuePropTypes';
|
||||
|
||||
const {getCurrentFiberStackAddendum} = ReactDebugCurrentFiber;
|
||||
let didWarnValDefaultVal = false;
|
||||
|
||||
type TextAreaWithWrapperState = HTMLTextAreaElement & {
|
||||
@@ -68,7 +67,7 @@ export function initWrapperState(element: Element, props: Object) {
|
||||
ReactControlledValuePropTypes.checkPropTypes(
|
||||
'textarea',
|
||||
props,
|
||||
getCurrentFiberStackAddendum,
|
||||
getCurrentFiberStackInDevOrNull,
|
||||
);
|
||||
if (
|
||||
props.value !== undefined &&
|
||||
|
||||
+2
-3
@@ -7,9 +7,8 @@
|
||||
|
||||
import warning from 'shared/warning';
|
||||
// TODO: direct imports like some-package/src/* are bad. Fix me.
|
||||
import ReactDebugCurrentFiber from 'react-reconciler/src/ReactDebugCurrentFiber';
|
||||
import {getCurrentFiberStackInDevOrNull} from 'react-reconciler/src/ReactCurrentFiber';
|
||||
|
||||
const {getCurrentFiberStackAddendum} = ReactDebugCurrentFiber;
|
||||
let validateDOMNesting = () => {};
|
||||
|
||||
if (__DEV__) {
|
||||
@@ -427,7 +426,7 @@ if (__DEV__) {
|
||||
}
|
||||
|
||||
const ancestorTag = invalidParentOrAncestor.tag;
|
||||
const addendum = getCurrentFiberStackAddendum();
|
||||
const addendum = getCurrentFiberStackInDevOrNull();
|
||||
|
||||
const warnKey =
|
||||
!!invalidParent + '|' + childTag + '|' + ancestorTag + '|' + addendum;
|
||||
|
||||
@@ -13,14 +13,14 @@ import type {ReactNodeList} from 'shared/ReactTypes';
|
||||
import './ReactNativeInjection';
|
||||
|
||||
import * as ReactNativeFiberRenderer from 'react-reconciler/inline.native';
|
||||
// TODO: direct imports like some-package/src/* are bad. Fix me.
|
||||
import {getStackByFiberInDevAndProd} from 'react-reconciler/src/ReactCurrentFiber';
|
||||
import * as ReactPortal from 'shared/ReactPortal';
|
||||
import * as ReactGenericBatching from 'events/ReactGenericBatching';
|
||||
import ReactVersion from 'shared/ReactVersion';
|
||||
// Module provided by RN:
|
||||
import UIManager from 'UIManager';
|
||||
|
||||
import {getStackAddendumByWorkInProgressFiber} from 'shared/ReactFiberComponentTreeHook';
|
||||
|
||||
import NativeMethodsMixin from './NativeMethodsMixin';
|
||||
import ReactNativeComponent from './ReactNativeComponent';
|
||||
import * as ReactNativeComponentTree from './ReactNativeComponentTree';
|
||||
@@ -80,7 +80,7 @@ function computeComponentStackForErrorReporting(reactTag: number): string {
|
||||
if (!fiber) {
|
||||
return '';
|
||||
}
|
||||
return getStackAddendumByWorkInProgressFiber(fiber);
|
||||
return getStackByFiberInDevAndProd(fiber);
|
||||
}
|
||||
|
||||
const roots = new Map();
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@
|
||||
|
||||
import type {Fiber} from './ReactFiber';
|
||||
|
||||
import {getStackAddendumByWorkInProgressFiber} from 'shared/ReactFiberComponentTreeHook';
|
||||
import {getStackByFiberInDevAndProd} from './ReactCurrentFiber';
|
||||
|
||||
export type CapturedValue<T> = {
|
||||
value: T,
|
||||
@@ -36,6 +36,6 @@ export function createCapturedValue<T>(
|
||||
return {
|
||||
value,
|
||||
source,
|
||||
stack: getStackAddendumByWorkInProgressFiber(source),
|
||||
stack: getStackByFiberInDevAndProd(source),
|
||||
};
|
||||
}
|
||||
|
||||
+12
-12
@@ -27,7 +27,6 @@ import {
|
||||
HostPortal,
|
||||
Fragment,
|
||||
} from 'shared/ReactTypeOfWork';
|
||||
import {getStackAddendumByWorkInProgressFiber} from 'shared/ReactFiberComponentTreeHook';
|
||||
import invariant from 'shared/invariant';
|
||||
import warning from 'shared/warning';
|
||||
|
||||
@@ -39,11 +38,12 @@ import {
|
||||
createFiberFromPortal,
|
||||
} from './ReactFiber';
|
||||
import {emptyRefsObject} from './ReactFiberClassComponent';
|
||||
import ReactDebugCurrentFiber from './ReactDebugCurrentFiber';
|
||||
import {
|
||||
getCurrentFiberStackInDevOrNull,
|
||||
getStackByFiberInDevAndProd,
|
||||
} from './ReactCurrentFiber';
|
||||
import {StrictMode} from './ReactTypeOfMode';
|
||||
|
||||
const {getCurrentFiberStackAddendum} = ReactDebugCurrentFiber;
|
||||
|
||||
let didWarnAboutMaps;
|
||||
let didWarnAboutStringRefInStrictMode;
|
||||
let ownerHasKeyUseWarning;
|
||||
@@ -80,7 +80,7 @@ if (__DEV__) {
|
||||
'Each child in an array or iterator should have a unique ' +
|
||||
'"key" prop. See https://fb.me/react-warning-keys for ' +
|
||||
'more information.' +
|
||||
(getCurrentFiberStackAddendum() || '');
|
||||
(getCurrentFiberStackInDevOrNull() || '');
|
||||
if (ownerHasKeyUseWarning[currentComponentErrorInfo]) {
|
||||
return;
|
||||
}
|
||||
@@ -91,7 +91,7 @@ if (__DEV__) {
|
||||
'Each child in an array or iterator should have a unique ' +
|
||||
'"key" prop. See https://fb.me/react-warning-keys for ' +
|
||||
'more information.%s',
|
||||
getCurrentFiberStackAddendum(),
|
||||
getCurrentFiberStackInDevOrNull(),
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -122,7 +122,7 @@ function coerceRef(
|
||||
'\n\nLearn more about using refs safely here:' +
|
||||
'\nhttps://fb.me/react-strict-mode-string-ref',
|
||||
mixedRef,
|
||||
getStackAddendumByWorkInProgressFiber(returnFiber),
|
||||
getStackByFiberInDevAndProd(returnFiber),
|
||||
);
|
||||
didWarnAboutStringRefInStrictMode[componentName] = true;
|
||||
}
|
||||
@@ -197,7 +197,7 @@ function throwOnInvalidObjectType(returnFiber: Fiber, newChild: Object) {
|
||||
addendum =
|
||||
' If you meant to render a collection of children, use an array ' +
|
||||
'instead.' +
|
||||
(getCurrentFiberStackAddendum() || '');
|
||||
(getCurrentFiberStackInDevOrNull() || '');
|
||||
}
|
||||
invariant(
|
||||
false,
|
||||
@@ -215,7 +215,7 @@ function warnOnFunctionType() {
|
||||
'Functions are not valid as a React child. This may happen if ' +
|
||||
'you return a Component instead of <Component /> from render. ' +
|
||||
'Or maybe you meant to call this function rather than return it.' +
|
||||
(getCurrentFiberStackAddendum() || '');
|
||||
(getCurrentFiberStackInDevOrNull() || '');
|
||||
|
||||
if (ownerHasFunctionTypeWarning[currentComponentErrorInfo]) {
|
||||
return;
|
||||
@@ -227,7 +227,7 @@ function warnOnFunctionType() {
|
||||
'Functions are not valid as a React child. This may happen if ' +
|
||||
'you return a Component instead of <Component /> from render. ' +
|
||||
'Or maybe you meant to call this function rather than return it.%s',
|
||||
getCurrentFiberStackAddendum() || '',
|
||||
getCurrentFiberStackInDevOrNull() || '',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -719,7 +719,7 @@ function ChildReconciler(shouldTrackSideEffects) {
|
||||
'duplicated and/or omitted — the behavior is unsupported and ' +
|
||||
'could change in a future version.%s',
|
||||
key,
|
||||
getCurrentFiberStackAddendum(),
|
||||
getCurrentFiberStackInDevOrNull(),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
@@ -912,7 +912,7 @@ function ChildReconciler(shouldTrackSideEffects) {
|
||||
'Using Maps as children is unsupported and will likely yield ' +
|
||||
'unexpected results. Convert it to a sequence/iterable of keyed ' +
|
||||
'ReactElements instead.%s',
|
||||
getCurrentFiberStackAddendum(),
|
||||
getCurrentFiberStackInDevOrNull(),
|
||||
);
|
||||
didWarnAboutMaps = true;
|
||||
}
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import {ReactDebugCurrentFrame} from 'shared/ReactGlobalSharedState';
|
||||
import {
|
||||
IndeterminateComponent,
|
||||
FunctionalComponent,
|
||||
ClassComponent,
|
||||
HostComponent,
|
||||
} from 'shared/ReactTypeOfWork';
|
||||
import describeComponentFrame from 'shared/describeComponentFrame';
|
||||
import getComponentName from 'shared/getComponentName';
|
||||
|
||||
import type {Fiber} from './ReactFiber';
|
||||
|
||||
type LifeCyclePhase = 'render' | 'getChildContext';
|
||||
|
||||
function describeFiber(fiber: Fiber): string {
|
||||
switch (fiber.tag) {
|
||||
case IndeterminateComponent:
|
||||
case FunctionalComponent:
|
||||
case ClassComponent:
|
||||
case HostComponent:
|
||||
const owner = fiber._debugOwner;
|
||||
const source = fiber._debugSource;
|
||||
const name = getComponentName(fiber);
|
||||
let ownerName = null;
|
||||
if (owner) {
|
||||
ownerName = getComponentName(owner);
|
||||
}
|
||||
return describeComponentFrame(name, source, ownerName);
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
export function getStackByFiberInDevAndProd(workInProgress: Fiber): string {
|
||||
let info = '';
|
||||
let node = workInProgress;
|
||||
do {
|
||||
info += describeFiber(node);
|
||||
node = node.return;
|
||||
} while (node);
|
||||
return info;
|
||||
}
|
||||
|
||||
export let current: Fiber | null = null;
|
||||
export let phase: LifeCyclePhase | null = null;
|
||||
|
||||
export function getCurrentFiberOwnerNameInDevOrNull(): string | null {
|
||||
if (__DEV__) {
|
||||
if (current === null) {
|
||||
return null;
|
||||
}
|
||||
const owner = current._debugOwner;
|
||||
if (owner !== null && typeof owner !== 'undefined') {
|
||||
return getComponentName(owner);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getCurrentFiberStackInDevOrNull(): string | null {
|
||||
if (__DEV__) {
|
||||
if (current === null) {
|
||||
return null;
|
||||
}
|
||||
// Safe because if current fiber exists, we are reconciling,
|
||||
// and it is guaranteed to be the work-in-progress version.
|
||||
return getStackByFiberInDevAndProd(current);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function resetCurrentFiber() {
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFrame.getCurrentStack = null;
|
||||
current = null;
|
||||
phase = null;
|
||||
}
|
||||
}
|
||||
|
||||
export function setCurrentFiber(fiber: Fiber) {
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackInDevOrNull;
|
||||
current = fiber;
|
||||
phase = null;
|
||||
}
|
||||
}
|
||||
|
||||
export function setCurrentPhase(lifeCyclePhase: LifeCyclePhase | null) {
|
||||
if (__DEV__) {
|
||||
phase = lifeCyclePhase;
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import {ReactDebugCurrentFrame} from 'shared/ReactGlobalSharedState';
|
||||
import {getStackAddendumByWorkInProgressFiber} from 'shared/ReactFiberComponentTreeHook';
|
||||
import getComponentName from 'shared/getComponentName';
|
||||
|
||||
import type {Fiber} from './ReactFiber';
|
||||
|
||||
type LifeCyclePhase = 'render' | 'getChildContext';
|
||||
|
||||
function getCurrentFiberOwnerName(): string | null {
|
||||
if (__DEV__) {
|
||||
const fiber = ReactDebugCurrentFiber.current;
|
||||
if (fiber === null) {
|
||||
return null;
|
||||
}
|
||||
const owner = fiber._debugOwner;
|
||||
if (owner !== null && typeof owner !== 'undefined') {
|
||||
return getComponentName(owner);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getCurrentFiberStackAddendum(): string | null {
|
||||
if (__DEV__) {
|
||||
const fiber = ReactDebugCurrentFiber.current;
|
||||
if (fiber === null) {
|
||||
return null;
|
||||
}
|
||||
// Safe because if current fiber exists, we are reconciling,
|
||||
// and it is guaranteed to be the work-in-progress version.
|
||||
return getStackAddendumByWorkInProgressFiber(fiber);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function resetCurrentFiber() {
|
||||
ReactDebugCurrentFrame.getCurrentStack = null;
|
||||
ReactDebugCurrentFiber.current = null;
|
||||
ReactDebugCurrentFiber.phase = null;
|
||||
}
|
||||
|
||||
function setCurrentFiber(fiber: Fiber) {
|
||||
ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackAddendum;
|
||||
ReactDebugCurrentFiber.current = fiber;
|
||||
ReactDebugCurrentFiber.phase = null;
|
||||
}
|
||||
|
||||
function setCurrentPhase(phase: LifeCyclePhase | null) {
|
||||
ReactDebugCurrentFiber.phase = phase;
|
||||
}
|
||||
|
||||
const ReactDebugCurrentFiber = {
|
||||
current: (null: Fiber | null),
|
||||
phase: (null: LifeCyclePhase | null),
|
||||
resetCurrentFiber,
|
||||
setCurrentFiber,
|
||||
setCurrentPhase,
|
||||
getCurrentFiberOwnerName,
|
||||
getCurrentFiberStackAddendum,
|
||||
};
|
||||
|
||||
export default ReactDebugCurrentFiber;
|
||||
+12
-14
@@ -50,7 +50,7 @@ import invariant from 'shared/invariant';
|
||||
import getComponentName from 'shared/getComponentName';
|
||||
import ReactStrictModeWarnings from './ReactStrictModeWarnings';
|
||||
import warning from 'shared/warning';
|
||||
import ReactDebugCurrentFiber from './ReactDebugCurrentFiber';
|
||||
import * as ReactCurrentFiber from './ReactCurrentFiber';
|
||||
import {cancelWorkTimer} from './ReactDebugFiberPerf';
|
||||
|
||||
import {applyDerivedStateFromProps} from './ReactFiberClassComponent';
|
||||
@@ -98,8 +98,6 @@ import {
|
||||
} from './ReactFiberClassComponent';
|
||||
import MAX_SIGNED_31_BIT_INT from './maxSigned31BitInt';
|
||||
|
||||
const {getCurrentFiberStackAddendum} = ReactDebugCurrentFiber;
|
||||
|
||||
let didWarnAboutBadClass;
|
||||
let didWarnAboutGetDerivedStateOnFunctionalComponent;
|
||||
let didWarnAboutStatelessRefs;
|
||||
@@ -170,9 +168,9 @@ function updateForwardRef(current, workInProgress) {
|
||||
let nextChildren;
|
||||
if (__DEV__) {
|
||||
ReactCurrentOwner.current = workInProgress;
|
||||
ReactDebugCurrentFiber.setCurrentPhase('render');
|
||||
ReactCurrentFiber.setCurrentPhase('render');
|
||||
nextChildren = render(nextProps, ref);
|
||||
ReactDebugCurrentFiber.setCurrentPhase(null);
|
||||
ReactCurrentFiber.setCurrentPhase(null);
|
||||
} else {
|
||||
nextChildren = render(nextProps, ref);
|
||||
}
|
||||
@@ -258,9 +256,9 @@ function updateFunctionalComponent(current, workInProgress) {
|
||||
|
||||
if (__DEV__) {
|
||||
ReactCurrentOwner.current = workInProgress;
|
||||
ReactDebugCurrentFiber.setCurrentPhase('render');
|
||||
ReactCurrentFiber.setCurrentPhase('render');
|
||||
nextChildren = fn(nextProps, context);
|
||||
ReactDebugCurrentFiber.setCurrentPhase(null);
|
||||
ReactCurrentFiber.setCurrentPhase(null);
|
||||
} else {
|
||||
nextChildren = fn(nextProps, context);
|
||||
}
|
||||
@@ -359,7 +357,7 @@ function finishClassComponent(
|
||||
}
|
||||
} else {
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFiber.setCurrentPhase('render');
|
||||
ReactCurrentFiber.setCurrentPhase('render');
|
||||
nextChildren = instance.render();
|
||||
if (
|
||||
debugRenderPhaseSideEffects ||
|
||||
@@ -368,7 +366,7 @@ function finishClassComponent(
|
||||
) {
|
||||
instance.render();
|
||||
}
|
||||
ReactDebugCurrentFiber.setCurrentPhase(null);
|
||||
ReactCurrentFiber.setCurrentPhase(null);
|
||||
} else {
|
||||
nextChildren = instance.render();
|
||||
}
|
||||
@@ -660,7 +658,7 @@ function mountIndeterminateComponent(
|
||||
}
|
||||
if (workInProgress.ref !== null) {
|
||||
let info = '';
|
||||
const ownerName = ReactDebugCurrentFiber.getCurrentFiberOwnerName();
|
||||
const ownerName = ReactCurrentFiber.getCurrentFiberOwnerNameInDevOrNull();
|
||||
if (ownerName) {
|
||||
info += '\n\nCheck the render method of `' + ownerName + '`.';
|
||||
}
|
||||
@@ -677,7 +675,7 @@ function mountIndeterminateComponent(
|
||||
'Stateless function components cannot be given refs. ' +
|
||||
'Attempts to access this ref will fail.%s%s',
|
||||
info,
|
||||
ReactDebugCurrentFiber.getCurrentFiberStackAddendum(),
|
||||
ReactCurrentFiber.getCurrentFiberStackInDevOrNull(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -935,7 +933,7 @@ function updateContextProvider(current, workInProgress, renderExpirationTime) {
|
||||
newProps,
|
||||
'prop',
|
||||
'Context.Provider',
|
||||
getCurrentFiberStackAddendum,
|
||||
ReactCurrentFiber.getCurrentFiberStackInDevOrNull,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1069,9 +1067,9 @@ function updateContextConsumer(current, workInProgress, renderExpirationTime) {
|
||||
let newChildren;
|
||||
if (__DEV__) {
|
||||
ReactCurrentOwner.current = workInProgress;
|
||||
ReactDebugCurrentFiber.setCurrentPhase('render');
|
||||
ReactCurrentFiber.setCurrentPhase('render');
|
||||
newChildren = render(newValue);
|
||||
ReactDebugCurrentFiber.setCurrentPhase(null);
|
||||
ReactCurrentFiber.setCurrentPhase(null);
|
||||
} else {
|
||||
newChildren = render(newValue);
|
||||
}
|
||||
|
||||
+6
-6
@@ -20,7 +20,6 @@ import type {ExpirationTime} from './ReactFiberExpirationTime';
|
||||
import type {CapturedValue, CapturedError} from './ReactCapturedValue';
|
||||
|
||||
import {enableProfilerTimer, enableSuspense} from 'shared/ReactFeatureFlags';
|
||||
import {getCommitTime} from './ReactProfilerTimer';
|
||||
import {
|
||||
ClassComponent,
|
||||
HostRoot,
|
||||
@@ -38,16 +37,17 @@ import {
|
||||
Snapshot,
|
||||
Update,
|
||||
} from 'shared/ReactTypeOfSideEffect';
|
||||
import {commitUpdateQueue} from './ReactUpdateQueue';
|
||||
import getComponentName from 'shared/getComponentName';
|
||||
import invariant from 'shared/invariant';
|
||||
import warning from 'shared/warning';
|
||||
|
||||
import {Sync} from './ReactFiberExpirationTime';
|
||||
import {onCommitUnmount} from './ReactFiberDevToolsHook';
|
||||
import {startPhaseTimer, stopPhaseTimer} from './ReactDebugFiberPerf';
|
||||
import getComponentName from 'shared/getComponentName';
|
||||
import {getStackAddendumByWorkInProgressFiber} from 'shared/ReactFiberComponentTreeHook';
|
||||
import {getStackByFiberInDevAndProd} from './ReactCurrentFiber';
|
||||
import {logCapturedError} from './ReactFiberErrorLogger';
|
||||
import {getCommitTime} from './ReactProfilerTimer';
|
||||
import {commitUpdateQueue} from './ReactUpdateQueue';
|
||||
import {
|
||||
getPublicInstance,
|
||||
supportsMutation,
|
||||
@@ -89,7 +89,7 @@ export function logError(boundary: Fiber, errorInfo: CapturedValue<mixed>) {
|
||||
const source = errorInfo.source;
|
||||
let stack = errorInfo.stack;
|
||||
if (stack === null && source !== null) {
|
||||
stack = getStackAddendumByWorkInProgressFiber(source);
|
||||
stack = getStackByFiberInDevAndProd(source);
|
||||
}
|
||||
|
||||
const capturedError: CapturedError = {
|
||||
@@ -373,7 +373,7 @@ function commitAttachRef(finishedWork: Fiber) {
|
||||
'Unexpected ref object provided for %s. ' +
|
||||
'Use either a ref-setter function or React.createRef().%s',
|
||||
getComponentName(finishedWork),
|
||||
getStackAddendumByWorkInProgressFiber(finishedWork),
|
||||
getStackByFiberInDevAndProd(finishedWork),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -17,7 +17,7 @@ import invariant from 'shared/invariant';
|
||||
import warning from 'shared/warning';
|
||||
import checkPropTypes from 'prop-types/checkPropTypes';
|
||||
|
||||
import ReactDebugCurrentFiber from './ReactDebugCurrentFiber';
|
||||
import * as ReactCurrentFiber from './ReactCurrentFiber';
|
||||
import {startPhaseTimer, stopPhaseTimer} from './ReactDebugFiberPerf';
|
||||
import {createCursor, push, pop} from './ReactFiberStack';
|
||||
|
||||
@@ -96,7 +96,7 @@ function getMaskedContext(
|
||||
context,
|
||||
'context',
|
||||
name,
|
||||
ReactDebugCurrentFiber.getCurrentFiberStackAddendum,
|
||||
ReactCurrentFiber.getCurrentFiberStackInDevOrNull,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -177,13 +177,13 @@ function processChildContext(fiber: Fiber, parentContext: Object): Object {
|
||||
|
||||
let childContext;
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFiber.setCurrentPhase('getChildContext');
|
||||
ReactCurrentFiber.setCurrentPhase('getChildContext');
|
||||
}
|
||||
startPhaseTimer(fiber, 'getChildContext');
|
||||
childContext = instance.getChildContext();
|
||||
stopPhaseTimer();
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFiber.setCurrentPhase(null);
|
||||
ReactCurrentFiber.setCurrentPhase(null);
|
||||
}
|
||||
for (let contextKey in childContext) {
|
||||
invariant(
|
||||
@@ -205,7 +205,7 @@ function processChildContext(fiber: Fiber, parentContext: Object): Object {
|
||||
// context from the parent component instance. The stack will be missing
|
||||
// because it's outside of the reconciliation, and so the pointer has not
|
||||
// been set. This is rare and doesn't matter. We'll also remove that API.
|
||||
ReactDebugCurrentFiber.getCurrentFiberStackAddendum,
|
||||
ReactCurrentFiber.getCurrentFiberStackInDevOrNull,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -55,7 +55,7 @@ import {
|
||||
} from './ReactFiberScheduler';
|
||||
import {createUpdate, enqueueUpdate} from './ReactUpdateQueue';
|
||||
import ReactFiberInstrumentation from './ReactFiberInstrumentation';
|
||||
import ReactDebugCurrentFiber from './ReactDebugCurrentFiber';
|
||||
import * as ReactCurrentFiber from './ReactCurrentFiber';
|
||||
|
||||
type OpaqueRoot = FiberRoot;
|
||||
|
||||
@@ -104,8 +104,8 @@ function scheduleRootUpdate(
|
||||
) {
|
||||
if (__DEV__) {
|
||||
if (
|
||||
ReactDebugCurrentFiber.phase === 'render' &&
|
||||
ReactDebugCurrentFiber.current !== null &&
|
||||
ReactCurrentFiber.phase === 'render' &&
|
||||
ReactCurrentFiber.current !== null &&
|
||||
!didWarnAboutNestedUpdates
|
||||
) {
|
||||
didWarnAboutNestedUpdates = true;
|
||||
@@ -115,7 +115,7 @@ function scheduleRootUpdate(
|
||||
'triggering nested component updates from render is not allowed. ' +
|
||||
'If necessary, trigger nested updates in componentDidUpdate.\n\n' +
|
||||
'Check the render method of %s.',
|
||||
getComponentName(ReactDebugCurrentFiber.current) || 'Unknown',
|
||||
getComponentName(ReactCurrentFiber.current) || 'Unknown',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+10
-11
@@ -12,7 +12,6 @@ import type {FiberRoot, Batch} from './ReactFiberRoot';
|
||||
import type {ExpirationTime} from './ReactFiberExpirationTime';
|
||||
|
||||
import ReactErrorUtils from 'shared/ReactErrorUtils';
|
||||
import {getStackAddendumByWorkInProgressFiber} from 'shared/ReactFiberComponentTreeHook';
|
||||
import {ReactCurrentOwner} from 'shared/ReactGlobalSharedState';
|
||||
import ReactStrictModeWarnings from './ReactStrictModeWarnings';
|
||||
import {
|
||||
@@ -56,7 +55,7 @@ import {
|
||||
} from './ReactFiberHostConfig';
|
||||
|
||||
import ReactFiberInstrumentation from './ReactFiberInstrumentation';
|
||||
import ReactDebugCurrentFiber from './ReactDebugCurrentFiber';
|
||||
import * as ReactCurrentFiber from './ReactCurrentFiber';
|
||||
import {
|
||||
now,
|
||||
scheduleDeferredCallback,
|
||||
@@ -185,13 +184,13 @@ if (__DEV__) {
|
||||
'is a no-op, but it indicates a memory leak in your application. To ' +
|
||||
'fix, cancel all subscriptions and asynchronous tasks in the ' +
|
||||
'componentWillUnmount method.%s',
|
||||
getStackAddendumByWorkInProgressFiber(fiber),
|
||||
ReactCurrentFiber.getStackByFiberInDevAndProd(fiber),
|
||||
);
|
||||
didWarnStateUpdateForUnmountedComponent[componentName] = true;
|
||||
};
|
||||
|
||||
warnAboutInvalidUpdates = function(instance: React$Component<any>) {
|
||||
switch (ReactDebugCurrentFiber.phase) {
|
||||
switch (ReactCurrentFiber.phase) {
|
||||
case 'getChildContext':
|
||||
if (didWarnSetStateChildContext) {
|
||||
return;
|
||||
@@ -363,7 +362,7 @@ function resetStack() {
|
||||
function commitAllHostEffects() {
|
||||
while (nextEffect !== null) {
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFiber.setCurrentFiber(nextEffect);
|
||||
ReactCurrentFiber.setCurrentFiber(nextEffect);
|
||||
}
|
||||
recordEffect();
|
||||
|
||||
@@ -422,7 +421,7 @@ function commitAllHostEffects() {
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFiber.resetCurrentFiber();
|
||||
ReactCurrentFiber.resetCurrentFiber();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -778,7 +777,7 @@ function completeUnitOfWork(workInProgress: Fiber): Fiber | null {
|
||||
// progress.
|
||||
const current = workInProgress.alternate;
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFiber.setCurrentFiber(workInProgress);
|
||||
ReactCurrentFiber.setCurrentFiber(workInProgress);
|
||||
}
|
||||
|
||||
const returnFiber = workInProgress.return;
|
||||
@@ -794,7 +793,7 @@ function completeUnitOfWork(workInProgress: Fiber): Fiber | null {
|
||||
stopWorkTimer(workInProgress);
|
||||
resetExpirationTime(workInProgress, nextRenderExpirationTime);
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFiber.resetCurrentFiber();
|
||||
ReactCurrentFiber.resetCurrentFiber();
|
||||
}
|
||||
|
||||
if (next !== null) {
|
||||
@@ -873,7 +872,7 @@ function completeUnitOfWork(workInProgress: Fiber): Fiber | null {
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFiber.resetCurrentFiber();
|
||||
ReactCurrentFiber.resetCurrentFiber();
|
||||
}
|
||||
|
||||
if (next !== null) {
|
||||
@@ -929,7 +928,7 @@ function performUnitOfWork(workInProgress: Fiber): Fiber | null {
|
||||
// See if beginning this work spawns more work.
|
||||
startWorkTimer(workInProgress);
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFiber.setCurrentFiber(workInProgress);
|
||||
ReactCurrentFiber.setCurrentFiber(workInProgress);
|
||||
}
|
||||
|
||||
if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) {
|
||||
@@ -957,7 +956,7 @@ function performUnitOfWork(workInProgress: Fiber): Fiber | null {
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
ReactDebugCurrentFiber.resetCurrentFiber();
|
||||
ReactCurrentFiber.resetCurrentFiber();
|
||||
if (isReplayingFailedUnitOfWork) {
|
||||
// Currently replaying a failed unit of work. This should be unreachable,
|
||||
// because the render phase is meant to be idempotent, and it should
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
|
||||
import type {Fiber} from './ReactFiber';
|
||||
|
||||
import {getStackByFiberInDevAndProd} from './ReactCurrentFiber';
|
||||
|
||||
import getComponentName from 'shared/getComponentName';
|
||||
import {getStackAddendumByWorkInProgressFiber} from 'shared/ReactFiberComponentTreeHook';
|
||||
import {StrictMode} from './ReactTypeOfMode';
|
||||
import lowPriorityWarning from 'shared/lowPriorityWarning';
|
||||
import warning from 'shared/warning';
|
||||
@@ -94,7 +95,7 @@ if (__DEV__) {
|
||||
});
|
||||
|
||||
if (lifecyclesWarningMesages.length > 0) {
|
||||
const strictRootComponentStack = getStackAddendumByWorkInProgressFiber(
|
||||
const strictRootComponentStack = getStackByFiberInDevAndProd(
|
||||
strictRoot,
|
||||
);
|
||||
|
||||
@@ -341,7 +342,7 @@ if (__DEV__) {
|
||||
});
|
||||
|
||||
const sortedNames = setToSortedString(uniqueNames);
|
||||
const strictRootComponentStack = getStackAddendumByWorkInProgressFiber(
|
||||
const strictRootComponentStack = getStackByFiberInDevAndProd(
|
||||
strictRoot,
|
||||
);
|
||||
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import type {Fiber} from 'react-reconciler/src/ReactFiber';
|
||||
|
||||
import {
|
||||
IndeterminateComponent,
|
||||
FunctionalComponent,
|
||||
ClassComponent,
|
||||
HostComponent,
|
||||
} from './ReactTypeOfWork';
|
||||
import describeComponentFrame from './describeComponentFrame';
|
||||
import getComponentName from './getComponentName';
|
||||
|
||||
function describeFiber(fiber: Fiber): string {
|
||||
switch (fiber.tag) {
|
||||
case IndeterminateComponent:
|
||||
case FunctionalComponent:
|
||||
case ClassComponent:
|
||||
case HostComponent:
|
||||
const owner = fiber._debugOwner;
|
||||
const source = fiber._debugSource;
|
||||
const name = getComponentName(fiber);
|
||||
let ownerName = null;
|
||||
if (owner) {
|
||||
ownerName = getComponentName(owner);
|
||||
}
|
||||
return describeComponentFrame(name, source, ownerName);
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
// This function can only be called with a work-in-progress fiber and
|
||||
// only during begin or complete phase. Do not call it under any other
|
||||
// circumstances.
|
||||
export function getStackAddendumByWorkInProgressFiber(
|
||||
workInProgress: Fiber,
|
||||
): string {
|
||||
let info = '';
|
||||
let node = workInProgress;
|
||||
do {
|
||||
info += describeFiber(node);
|
||||
// Otherwise this return pointer might point to the wrong tree:
|
||||
node = node.return;
|
||||
} while (node);
|
||||
return info;
|
||||
}
|
||||
Reference in New Issue
Block a user