Skip to content

Commit 6796336

Browse files
committed
Add dev-only ReactDebugCurrentFiber for warnings
The goal is to use ReactCurrentOwner less and rely on ReactDebugCurrentFiber for warning owner name and stack.
1 parent 8f544a7 commit 6796336

18 files changed

Lines changed: 178 additions & 78 deletions

scripts/fiber/tests-failing.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ src/renderers/dom/shared/__tests__/ReactDOM-test.js
2121

2222
src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
2323
* should warn for children on void elements
24-
* should report component containing invalid styles
2524
* should clean up input value tracking
2625
* should clean up input textarea tracking
2726
* gives source code refs for unknown prop warning

scripts/fiber/tests-passing-except-dev.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
1212
* should warn for unknown prop
1313
* should group multiple unknown prop warnings together
1414
* should warn for onDblClick prop
15-
* should emit a warning once for a named custom component using shady DOM
1615
* should not warn when server-side rendering `onScroll`
1716
* warns on invalid nesting
1817
* warns on invalid nesting at root

scripts/fiber/tests-passing.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,8 @@ src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
653653
* should warn on upper case HTML tags, not SVG nor custom tags
654654
* should warn against children for void elements
655655
* should warn against dangerouslySetInnerHTML for void elements
656+
* should include owner rather than parent in warnings
657+
* should emit a warning once for a named custom component using shady DOM
656658
* should emit a warning once for an unnamed custom component using shady DOM
657659
* should treat menuitem as a void element but still create the closing tag
658660
* should validate against multiple children props
@@ -671,6 +673,7 @@ src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
671673
* should validate against multiple children props
672674
* should warn about contentEditable and children
673675
* should validate against invalid styles
676+
* should report component containing invalid styles
674677
* should properly escape text content and attributes values
675678
* unmounts children before unsetting DOM node info
676679
* should warn about the `onScroll` issue when unsupported (IE8)

src/isomorphic/hooks/ReactComponentTreeHook.js

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -353,25 +353,17 @@ var ReactComponentTreeHook = {
353353
var currentOwner = ReactCurrentOwner.current;
354354
if (currentOwner) {
355355
if (typeof currentOwner.tag === 'number') {
356-
const fiber = ((currentOwner : any) : Fiber);
357-
info += ReactComponentTreeHook.getStackAddendumByFiber(fiber);
356+
const workInProgress = ((currentOwner : any) : Fiber);
357+
// Safe because if current owner exists, we are reconciling,
358+
// and it is guaranteed to be the work-in-progress version.
359+
info += ReactComponentTreeHook.getStackAddendumByWorkInProgressFiber(workInProgress);
358360
} else if (typeof currentOwner._debugID === 'number') {
359361
info += ReactComponentTreeHook.getStackAddendumByID(currentOwner._debugID);
360362
}
361363
}
362364
return info;
363365
},
364366

365-
getStackAddendumByFiber(fiber : Fiber) : string {
366-
var info = '';
367-
var node = fiber;
368-
do {
369-
info += describeFiber(node);
370-
node = node.return;
371-
} while (node);
372-
return info;
373-
},
374-
375367
getStackAddendumByID(id: ?DebugID): string {
376368
var info = '';
377369
while (id) {
@@ -381,6 +373,20 @@ var ReactComponentTreeHook = {
381373
return info;
382374
},
383375

376+
// This function can only be called with a work-in-progress fiber and
377+
// only during begin or complete phase. Do not call it under any other
378+
// circumstances.
379+
getStackAddendumByWorkInProgressFiber(workInProgress : Fiber) : string {
380+
var info = '';
381+
var node = workInProgress;
382+
do {
383+
info += describeFiber(node);
384+
// Otherwise this return pointer might point to the wrong tree:
385+
node = node.return;
386+
} while (node);
387+
return info;
388+
},
389+
384390
getChildIDs(id: DebugID): Array<DebugID> {
385391
var item = getItem(id);
386392
return item ? item.childIDs : [];

src/renderers/dom/fiber/ReactDOMFiberComponent.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ var ReactDOMFiberInput = require('ReactDOMFiberInput');
2525
var ReactDOMFiberOption = require('ReactDOMFiberOption');
2626
var ReactDOMFiberSelect = require('ReactDOMFiberSelect');
2727
var ReactDOMFiberTextarea = require('ReactDOMFiberTextarea');
28+
var { getCurrentFiberOwnerName } = require('ReactDebugCurrentFiber');
2829

2930
var emptyFunction = require('emptyFunction');
3031
var focusNode = require('focusNode');
31-
var getCurrentOwnerName = require('getCurrentOwnerName');
3232
var invariant = require('invariant');
3333
var isEventSupported = require('isEventSupported');
3434
var setInnerHTML = require('setInnerHTML');
@@ -56,7 +56,7 @@ var DOC_FRAGMENT_TYPE = 11;
5656

5757

5858
function getDeclarationErrorAddendum() {
59-
var ownerName = getCurrentOwnerName();
59+
var ownerName = getCurrentFiberOwnerName();
6060
if (ownerName) {
6161
return ' This DOM node was rendered by `' + ownerName + '`.';
6262
}
@@ -436,7 +436,7 @@ function updateDOMProperties(
436436
CSSPropertyOperations.setValueForStyles(
437437
domElement,
438438
styleUpdates,
439-
componentPlaceholder // TODO: Change CSSPropertyOperations to use getCurrentOwnerName.
439+
componentPlaceholder // TODO: Change CSSPropertyOperations to use getCurrentFiberOwnerName.
440440
);
441441
}
442442
}
@@ -529,7 +529,7 @@ var ReactDOMFiberComponent = {
529529
false,
530530
'%s is using shady DOM. Using shady DOM with React can ' +
531531
'cause things to break subtly.',
532-
getCurrentOwnerName() || 'A component'
532+
getCurrentFiberOwnerName() || 'A component'
533533
);
534534
didWarnShadyDOM = true;
535535
}

src/renderers/dom/fiber/wrappers/ReactDOMFiberInput.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ type InputWithWrapperState = HTMLInputElement & {
2323
var DOMPropertyOperations = require('DOMPropertyOperations');
2424
var ReactControlledValuePropTypes = require('ReactControlledValuePropTypes');
2525
var ReactDOMComponentTree = require('ReactDOMComponentTree');
26+
var { getCurrentFiberOwnerName } = require('ReactDebugCurrentFiber');
2627

27-
var getCurrentOwnerName = require('getCurrentOwnerName');
2828
var invariant = require('invariant');
2929
var warning = require('warning');
3030

@@ -86,7 +86,7 @@ var ReactDOMInput = {
8686
ReactControlledValuePropTypes.checkPropTypes(
8787
'input',
8888
props,
89-
getCurrentOwnerName()
89+
getCurrentFiberOwnerName()
9090
);
9191

9292
if (
@@ -102,7 +102,7 @@ var ReactDOMInput = {
102102
'both). Decide between using a controlled or uncontrolled input ' +
103103
'element and remove one of these props. More info: ' +
104104
'https://fb.me/react-controlled-components',
105-
getCurrentOwnerName() || 'A component',
105+
getCurrentFiberOwnerName() || 'A component',
106106
props.type
107107
);
108108
didWarnCheckedDefaultChecked = true;
@@ -120,7 +120,7 @@ var ReactDOMInput = {
120120
'both). Decide between using a controlled or uncontrolled input ' +
121121
'element and remove one of these props. More info: ' +
122122
'https://fb.me/react-controlled-components',
123-
getCurrentOwnerName() || 'A component',
123+
getCurrentFiberOwnerName() || 'A component',
124124
props.type
125125
);
126126
didWarnValueDefaultValue = true;
@@ -151,7 +151,7 @@ var ReactDOMInput = {
151151
'Input elements should not switch from uncontrolled to controlled (or vice versa). ' +
152152
'Decide between using a controlled or uncontrolled input ' +
153153
'element for the lifetime of the component. More info: https://fb.me/react-controlled-components',
154-
getCurrentOwnerName() || 'A component',
154+
getCurrentFiberOwnerName() || 'A component',
155155
props.type
156156
);
157157
didWarnUncontrolledToControlled = true;
@@ -163,7 +163,7 @@ var ReactDOMInput = {
163163
'Input elements should not switch from controlled to uncontrolled (or vice versa). ' +
164164
'Decide between using a controlled or uncontrolled input ' +
165165
'element for the lifetime of the component. More info: https://fb.me/react-controlled-components',
166-
getCurrentOwnerName() || 'A component',
166+
getCurrentFiberOwnerName() || 'A component',
167167
props.type
168168
);
169169
didWarnControlledToUncontrolled = true;

src/renderers/dom/fiber/wrappers/ReactDOMFiberSelect.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,13 @@ type SelectWithWrapperState = HTMLSelectElement & {
2020
};
2121

2222
var ReactControlledValuePropTypes = require('ReactControlledValuePropTypes');
23-
24-
var getCurrentOwnerName = require('getCurrentOwnerName');
23+
var { getCurrentFiberOwnerName } = require('ReactDebugCurrentFiber');
2524
var warning = require('warning');
2625

2726
var didWarnValueDefaultValue = false;
2827

2928
function getDeclarationErrorAddendum() {
30-
var ownerName = getCurrentOwnerName();
29+
var ownerName = getCurrentFiberOwnerName();
3130
if (ownerName) {
3231
return ' Check the render method of `' + ownerName + '`.';
3332
}
@@ -43,7 +42,7 @@ function checkSelectPropTypes(props) {
4342
ReactControlledValuePropTypes.checkPropTypes(
4443
'select',
4544
props,
46-
getCurrentOwnerName()
45+
getCurrentFiberOwnerName()
4746
);
4847

4948
for (var i = 0; i < valuePropNames.length; i++) {

src/renderers/dom/fiber/wrappers/ReactDOMFiberTextarea.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ type TextAreaWithWrapperState = HTMLTextAreaElement & {
1919
};
2020

2121
var ReactControlledValuePropTypes = require('ReactControlledValuePropTypes');
22+
var { getCurrentFiberOwnerName } = require('ReactDebugCurrentFiber');
2223

23-
var getCurrentOwnerName = require('getCurrentOwnerName');
2424
var invariant = require('invariant');
2525
var warning = require('warning');
2626

@@ -69,7 +69,7 @@ var ReactDOMTextarea = {
6969
ReactControlledValuePropTypes.checkPropTypes(
7070
'textarea',
7171
props,
72-
getCurrentOwnerName()
72+
getCurrentFiberOwnerName()
7373
);
7474
if (
7575
props.value !== undefined &&

src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,33 @@ describe('ReactDOMComponent', () => {
848848
);
849849
});
850850

851+
it('should include owner rather than parent in warnings', () => {
852+
var container = document.createElement('div');
853+
854+
function Parent(props) {
855+
return props.children;
856+
}
857+
function Owner() {
858+
// We're using the input dangerouslySetInnerHTML invariant but the
859+
// exact error doesn't matter as long as we have a way to verify
860+
// that warnings and invariants contain owner rather than parent name.
861+
return (
862+
<Parent>
863+
<input dangerouslySetInnerHTML={{__html: 'content'}} />
864+
</Parent>
865+
);
866+
}
867+
868+
expect(function() {
869+
ReactDOM.render(
870+
<Owner />,
871+
container
872+
);
873+
}).toThrowError(
874+
'This DOM node was rendered by `Owner`.'
875+
);
876+
});
877+
851878
it('should emit a warning once for a named custom component using shady DOM', () => {
852879
if (ReactDOMFeatureFlags.useCreateElement) {
853880
spyOn(console, 'error');

src/renderers/shared/fiber/ReactChildFiber.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ var getIteratorFn = require('getIteratorFn');
3838
var invariant = require('invariant');
3939

4040
if (__DEV__) {
41-
var ReactComponentTreeHook = require('ReactComponentTreeHook');
42-
var { getStackAddendumByFiber } = ReactComponentTreeHook;
41+
var { getCurrentFiberStackAddendum } = require('ReactDebugCurrentFiber');
4342
var warning = require('warning');
4443
}
4544

@@ -549,7 +548,6 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
549548

550549
function warnOnDuplicateKey(
551550
child : mixed,
552-
returnFiber : Fiber,
553551
knownKeys : Set<string> | null
554552
) : Set<string> | null {
555553
if (__DEV__) {
@@ -580,7 +578,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
580578
'`%s`. Child keys must be unique; when two children share a key, ' +
581579
'only the first child will be used.%s',
582580
key,
583-
getStackAddendumByFiber(returnFiber)
581+
getCurrentFiberStackAddendum()
584582
);
585583
break;
586584
default:
@@ -620,7 +618,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
620618
let knownKeys = null;
621619
for (let i = 0; i < newChildren.length; i++) {
622620
const child = newChildren[i];
623-
knownKeys = warnOnDuplicateKey(child, returnFiber, knownKeys);
621+
knownKeys = warnOnDuplicateKey(child, knownKeys);
624622
}
625623
}
626624

@@ -776,7 +774,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
776774
let step = newChildren.next();
777775
for (; !step.done; step = newChildren.next()) {
778776
const child = step.value;
779-
knownKeys = warnOnDuplicateKey(child, returnFiber, knownKeys);
777+
knownKeys = warnOnDuplicateKey(child, knownKeys);
780778
}
781779
}
782780

0 commit comments

Comments
 (0)