@samitouri / QOS-React / commits / 1c89cb62fd

Use ReactDebugCurrentFrame.getStackAddendum() in element validator (#13198)

Instead of wrapping ReactDebugCurrentFrame.getStackAddendum() call into a custom wrapper inside ReactElementValidator, "teach" the main ReactDebugCurrentFrame.getStackAddendum() to take currently validating element into account.

Dan Abramov committed Jul 12, 2018 at 16:18 UTC 1c89cb62fdd686a00351dfabc689571081edbd1a
2 files changed +51 -36
packages/react/src/ReactDebugCurrentFrame.js
+31 -3
@@ -7,18 +7,46 @@
7 * @flow
8 */
9
10 +import type {ReactElement} from 'shared/ReactElementType';
11 +
12 +import describeComponentFrame from 'shared/describeComponentFrame';
13 +import getComponentName from 'shared/getComponentName';
14 +
15 const ReactDebugCurrentFrame = {};
16
17 +let currentlyValidatingElement = (null: null | ReactElement);
18 +
19 +export function setCurrentlyValidatingElement(element: null | ReactElement) {
20 + if (__DEV__) {
21 + currentlyValidatingElement = element;
22 + }
23 +}
24 +
25 if (__DEV__) {
13 - // Component that is being worked on
26 + // Stack implementation injected by the current renderer.
27 ReactDebugCurrentFrame.getCurrentStack = (null: null | (() => string));
28
29 ReactDebugCurrentFrame.getStackAddendum = function(): string {
30 + let stack = '';
31 +
32 + // Add an extra top frame while an element is being validated
33 + if (currentlyValidatingElement) {
34 + const name = getComponentName(currentlyValidatingElement.type);
35 + const owner = currentlyValidatingElement._owner;
36 + stack += describeComponentFrame(
37 + name,
38 + currentlyValidatingElement._source,
39 + owner && getComponentName(owner.type),
40 + );
41 + }
42 +
43 + // Delegate to the injected renderer-specific implementation
44 const impl = ReactDebugCurrentFrame.getCurrentStack;
45 if (impl) {
19 - return impl() || '';
46 + stack += impl() || '';
47 }
21 - return '';
48 +
49 + return stack;
50 };
51 }
52
packages/react/src/ReactElementValidator.js
+20 -33
@@ -13,7 +13,6 @@
13 */
14
15 import lowPriorityWarning from 'shared/lowPriorityWarning';
16 -import describeComponentFrame from 'shared/describeComponentFrame';
16 import isValidElementType from 'shared/isValidElementType';
17 import getComponentName from 'shared/getComponentName';
18 import {
@@ -26,32 +25,14 @@ import warning from 'shared/warning';
25
26 import ReactCurrentOwner from './ReactCurrentOwner';
27 import {isValidElement, createElement, cloneElement} from './ReactElement';
29 -import ReactDebugCurrentFrame from './ReactDebugCurrentFrame';
28 +import ReactDebugCurrentFrame, {
29 + setCurrentlyValidatingElement,
30 +} from './ReactDebugCurrentFrame';
31
31 -let currentlyValidatingElement;
32 let propTypesMisspellWarningShown;
33
34 -let getStackAddendum = () => {};
35 -
34 if (__DEV__) {
37 - currentlyValidatingElement = null;
38 -
35 propTypesMisspellWarningShown = false;
40 -
41 - getStackAddendum = function(): string {
42 - let stack = '';
43 - if (currentlyValidatingElement) {
44 - const name = getComponentName(currentlyValidatingElement.type);
45 - const owner = currentlyValidatingElement._owner;
46 - stack += describeComponentFrame(
47 - name,
48 - currentlyValidatingElement._source,
49 - owner && getComponentName(owner.type),
50 - );
51 - }
52 - stack += ReactDebugCurrentFrame.getStackAddendum();
53 - return stack;
54 - };
36 }
37
38 function getDeclarationErrorAddendum() {
@@ -138,7 +119,7 @@ function validateExplicitKey(element, parentType) {
119 )}.`;
120 }
121
141 - currentlyValidatingElement = element;
122 + setCurrentlyValidatingElement(element);
123 if (__DEV__) {
124 warning(
125 false,
@@ -146,10 +127,10 @@ function validateExplicitKey(element, parentType) {
127 '%s%s See https://fb.me/react-warning-keys for more information.%s',
128 currentComponentErrorInfo,
129 childOwner,
149 - getStackAddendum(),
130 + ReactDebugCurrentFrame.getStackAddendum(),
131 );
132 }
152 - currentlyValidatingElement = null;
133 + setCurrentlyValidatingElement(null);
134 }
135
136 /**
@@ -221,9 +202,15 @@ function validatePropTypes(element) {
202 return;
203 }
204 if (propTypes) {
224 - currentlyValidatingElement = element;
225 - checkPropTypes(propTypes, element.props, 'prop', name, getStackAddendum);
226 - currentlyValidatingElement = null;
205 + setCurrentlyValidatingElement(element);
206 + checkPropTypes(
207 + propTypes,
208 + element.props,
209 + 'prop',
210 + name,
211 + ReactDebugCurrentFrame.getStackAddendum,
212 + );
213 + setCurrentlyValidatingElement(null);
214 } else if (type.PropTypes !== undefined && !propTypesMisspellWarningShown) {
215 propTypesMisspellWarningShown = true;
216 warning(
@@ -246,7 +233,7 @@ function validatePropTypes(element) {
233 * @param {ReactElement} fragment
234 */
235 function validateFragmentProps(fragment) {
249 - currentlyValidatingElement = fragment;
236 + setCurrentlyValidatingElement(fragment);
237
238 const keys = Object.keys(fragment.props);
239 for (let i = 0; i < keys.length; i++) {
@@ -257,7 +244,7 @@ function validateFragmentProps(fragment) {
244 'Invalid prop `%s` supplied to `React.Fragment`. ' +
245 'React.Fragment can only have `key` and `children` props.%s',
246 key,
260 - getStackAddendum(),
247 + ReactDebugCurrentFrame.getStackAddendum(),
248 );
249 break;
250 }
@@ -267,11 +254,11 @@ function validateFragmentProps(fragment) {
254 warning(
255 false,
256 'Invalid attribute `ref` supplied to `React.Fragment`.%s',
270 - getStackAddendum(),
257 + ReactDebugCurrentFrame.getStackAddendum(),
258 );
259 }
260
274 - currentlyValidatingElement = null;
261 + setCurrentlyValidatingElement(null);
262 }
263
264 export function createElementWithValidation(type, props, children) {
@@ -299,7 +286,7 @@ export function createElementWithValidation(type, props, children) {
286 info += getDeclarationErrorAddendum();
287 }
288
302 - info += getStackAddendum();
289 + info += ReactDebugCurrentFrame.getStackAddendum();
290
291 let typeString;
292 if (type === null) {