Skip to content

Commit 033fa98

Browse files
committed
Remove closure in checkReactTypeSpec by tracking stack info globally
There's a lot of overlap between ReactCurrentOwner, ReactDebugCurrentFrame, and ReactDebugCurrentFiber that should be consolidated.
1 parent fc18ebc commit 033fa98

File tree

7 files changed

+100
-56
lines changed

7 files changed

+100
-56
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* Copyright 2013-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
* @providesModule ReactDebugCurrentFrame
10+
* @flow
11+
*/
12+
13+
'use strict';
14+
15+
import type { Fiber } from 'ReactFiber';
16+
import type { DebugID } from 'ReactInstanceType';
17+
18+
if (__DEV__) {
19+
var {
20+
getStackAddendumByID,
21+
getStackAddendumByWorkInProgressFiber,
22+
getCurrentStackAddendum,
23+
} = require('ReactComponentTreeHook');
24+
}
25+
26+
const ReactDebugCurrentFrame = {
27+
// Component that is being worked on
28+
current: (null : Fiber | DebugID | null),
29+
30+
// Element that is being cloned or created
31+
element: (null : *),
32+
33+
getStackAddendum() : string | null {
34+
let stack = null;
35+
if (__DEV__) {
36+
const current = ReactDebugCurrentFrame.current;
37+
const element = ReactDebugCurrentFrame.element;
38+
if (current !== null) {
39+
if (typeof current === 'number') {
40+
// DebugID from Stack.
41+
const debugID = current;
42+
stack = getStackAddendumByID(debugID);
43+
} else if (typeof current.tag === 'number') {
44+
// This is a Fiber.
45+
// The stack will only be correct if this is a work in progress
46+
// version and we're calling it during reconciliation.
47+
const workInProgress = current;
48+
stack = getStackAddendumByWorkInProgressFiber(workInProgress);
49+
}
50+
} else if (element !== null) {
51+
stack = getCurrentStackAddendum(element);
52+
}
53+
}
54+
return stack;
55+
},
56+
};
57+
58+
module.exports = ReactDebugCurrentFrame;

src/isomorphic/classic/element/ReactElementValidator.js

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ var checkReactTypeSpec = require('checkReactTypeSpec');
2727
var canDefineProperty = require('canDefineProperty');
2828
var getComponentName = require('getComponentName');
2929
var getIteratorFn = require('getIteratorFn');
30-
var warning = require('warning');
30+
31+
if (__DEV__) {
32+
var warning = require('warning');
33+
var ReactDebugCurrentFrame = require('ReactDebugCurrentFrame');
34+
}
3135

3236
function getDeclarationErrorAddendum() {
3337
if (ReactCurrentOwner.current) {
@@ -181,9 +185,7 @@ function validatePropTypes(element) {
181185
componentClass.propTypes,
182186
element.props,
183187
'prop',
184-
name,
185-
element,
186-
null
188+
name
187189
);
188190
}
189191
if (typeof componentClass.getDefaultProps === 'function') {
@@ -248,6 +250,10 @@ var ReactElementValidator = {
248250
return element;
249251
}
250252

253+
if (__DEV__) {
254+
ReactDebugCurrentFrame.element = element;
255+
}
256+
251257
// Skip key warning if the type isn't valid since our key validation logic
252258
// doesn't expect a non-string/function type and can throw confusing errors.
253259
// We don't want exception behavior to differ between dev and prod.
@@ -261,6 +267,10 @@ var ReactElementValidator = {
261267

262268
validatePropTypes(element);
263269

270+
if (__DEV__) {
271+
ReactDebugCurrentFrame.element = null;
272+
}
273+
264274
return element;
265275
},
266276

@@ -301,10 +311,16 @@ var ReactElementValidator = {
301311

302312
cloneElement: function(element, props, children) {
303313
var newElement = ReactElement.cloneElement.apply(this, arguments);
314+
if (__DEV__) {
315+
ReactDebugCurrentFrame.element = newElement;
316+
}
304317
for (var i = 2; i < arguments.length; i++) {
305318
validateChildKeys(arguments[i], newElement.type);
306319
}
307320
validatePropTypes(newElement);
321+
if (__DEV__) {
322+
ReactDebugCurrentFrame.element = null;
323+
}
308324
return newElement;
309325
},
310326

src/isomorphic/classic/types/__tests__/ReactPropTypes-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ function getPropTypeWarningMessage(propTypes, object, componentName) {
3232
console.error.calls.reset();
3333
}
3434
resetWarningCache();
35-
checkReactTypeSpec(propTypes, object, 'prop', 'testComponent', null, null);
35+
checkReactTypeSpec(propTypes, object, 'prop', 'testComponent');
3636
const callCount = console.error.calls.count();
3737
if (callCount > 1) {
3838
throw new Error('Too many warnings.');

src/isomorphic/classic/types/checkPropTypes.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ function checkPropTypes(typeSpecs, values, location, componentName, getStack) {
7575
'Failed %s type: %s%s',
7676
location,
7777
error.message,
78-
stack,
78+
stack != null ? stack : '',
7979
);
8080
}
8181
}

src/renderers/shared/fiber/ReactFiberContext.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const {
3434

3535
if (__DEV__) {
3636
var checkReactTypeSpec = require('checkReactTypeSpec');
37+
var ReactDebugCurrentFrame = require('ReactDebugCurrentFrame');
3738
var warnedAboutMissingGetChildContext = {};
3839
}
3940

@@ -91,7 +92,9 @@ exports.getMaskedContext = function(workInProgress : Fiber, unmaskedContext : Ob
9192

9293
if (__DEV__) {
9394
const name = getComponentName(workInProgress);
94-
checkReactTypeSpec(contextTypes, context, 'context', name, null, workInProgress);
95+
ReactDebugCurrentFrame.current = workInProgress;
96+
checkReactTypeSpec(contextTypes, context, 'context', name);
97+
ReactDebugCurrentFrame.current = null;
9598
}
9699

97100
// Cache unmasked context so we can avoid recreating masked context unless necessary.
@@ -182,7 +185,9 @@ function processChildContext(fiber : Fiber, parentContext : Object, isReconcilin
182185
// assume anything about the given fiber. We won't pass it down if we aren't sure.
183186
// TODO: remove this hack when we delete unstable_renderSubtree in Fiber.
184187
const workInProgress = isReconciling ? fiber : null;
185-
checkReactTypeSpec(childContextTypes, childContext, 'child context', name, null, workInProgress);
188+
ReactDebugCurrentFrame.current = workInProgress;
189+
checkReactTypeSpec(childContextTypes, childContext, 'child context', name);
190+
ReactDebugCurrentFrame.current = null;
186191
}
187192
return {...parentContext, ...childContext};
188193
}

src/renderers/shared/stack/reconciler/ReactCompositeComponent.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ var ReactReconciler = require('ReactReconciler');
2424

2525
if (__DEV__) {
2626
var checkReactTypeSpec = require('checkReactTypeSpec');
27+
var ReactDebugCurrentFrame = require('ReactDebugCurrentFrame');
2728
var warningAboutMissingGetChildContext = {};
2829
}
2930

@@ -731,14 +732,14 @@ var ReactCompositeComponent = {
731732
location: string,
732733
) {
733734
if (__DEV__) {
735+
ReactDebugCurrentFrame.current = this._debugID;
734736
checkReactTypeSpec(
735737
typeSpecs,
736738
values,
737739
location,
738-
this.getName(),
739-
null,
740-
this._debugID
740+
this.getName()
741741
);
742+
ReactDebugCurrentFrame.current = null;
742743
}
743744
},
744745

src/shared/types/checkReactTypeSpec.js

Lines changed: 9 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -13,57 +13,21 @@
1313

1414
var checkPropTypes = require('checkPropTypes');
1515

16-
var ReactComponentTreeHook;
17-
18-
if (
19-
typeof process !== 'undefined' &&
20-
process.env &&
21-
process.env.NODE_ENV === 'test'
22-
) {
23-
// Temporary hack.
24-
// Inline requires don't work well with Jest:
25-
// https://github.com/facebook/react/issues/7240
26-
// Remove the inline requires when we don't need them anymore:
27-
// https://github.com/facebook/react/pull/7178
28-
ReactComponentTreeHook = require('ReactComponentTreeHook');
29-
}
16+
var { getStackAddendum } = require('ReactDebugCurrentFrame');
3017

3118
function checkReactTypeSpec(
3219
typeSpecs,
3320
values,
3421
location: string,
35-
componentName,
36-
element,
37-
// It is only safe to pass fiber if it is the work-in-progress version, and
38-
// only during reconciliation (begin and complete phase).
39-
workInProgressOrDebugID
22+
componentName
4023
) {
41-
function getStack() {
42-
let stack = '';
43-
if (__DEV__) {
44-
if (!ReactComponentTreeHook) {
45-
ReactComponentTreeHook = require('ReactComponentTreeHook');
46-
}
47-
if (workInProgressOrDebugID != null) {
48-
if (typeof workInProgressOrDebugID === 'number') {
49-
// DebugID from Stack.
50-
const debugID = workInProgressOrDebugID;
51-
stack = ReactComponentTreeHook.getStackAddendumByID(debugID);
52-
} else if (typeof workInProgressOrDebugID.tag === 'number') {
53-
// This is a Fiber.
54-
// The stack will only be correct if this is a work in progress
55-
// version and we're calling it during reconciliation.
56-
const workInProgress = workInProgressOrDebugID;
57-
stack = ReactComponentTreeHook.getStackAddendumByWorkInProgressFiber(workInProgress);
58-
}
59-
} else if (element !== null) {
60-
stack = ReactComponentTreeHook.getCurrentStackAddendum(element);
61-
}
62-
}
63-
return stack;
64-
}
65-
66-
checkPropTypes(typeSpecs, values, location, componentName, getStack);
24+
checkPropTypes(
25+
typeSpecs,
26+
values,
27+
location,
28+
componentName,
29+
getStackAddendum
30+
);
6731
}
6832

6933
module.exports = checkReactTypeSpec;

0 commit comments

Comments
 (0)