mirror of
https://github.com/hanzoai/react.git
synced 2026-09-24 17:02:27 +00:00
Include the function name for context on invalid function child (#28362)
Also warn for symbols. It's weird because for objects we throw a hard error but functions we do a dev only check. Mainly because we have an object branch anyway. In the object branch we have some built-ins that have bad errors like forwardRef and memo but since they're going to become functions later, I didn't bother updating those. Once they're functions those names will be part of this.
This commit is contained in:
committed by
GitHub
parent
f59cbb8b2d
commit
d0d8fc97cd
+10
-5
@@ -635,8 +635,9 @@ describe('ReactComponent', () => {
|
||||
});
|
||||
}).toErrorDev(
|
||||
'Warning: Functions are not valid as a React child. This may happen if ' +
|
||||
'you return a Component instead of <Component /> from render. ' +
|
||||
'you return Foo instead of <Foo /> from render. ' +
|
||||
'Or maybe you meant to call this function rather than return it.\n' +
|
||||
' <Foo>{Foo}</Foo>\n' +
|
||||
' in Foo (at **)',
|
||||
);
|
||||
});
|
||||
@@ -656,8 +657,9 @@ describe('ReactComponent', () => {
|
||||
});
|
||||
}).toErrorDev(
|
||||
'Warning: Functions are not valid as a React child. This may happen if ' +
|
||||
'you return a Component instead of <Component /> from render. ' +
|
||||
'you return Foo instead of <Foo /> from render. ' +
|
||||
'Or maybe you meant to call this function rather than return it.\n' +
|
||||
' <Foo>{Foo}</Foo>\n' +
|
||||
' in Foo (at **)',
|
||||
);
|
||||
});
|
||||
@@ -678,8 +680,9 @@ describe('ReactComponent', () => {
|
||||
});
|
||||
}).toErrorDev(
|
||||
'Warning: Functions are not valid as a React child. This may happen if ' +
|
||||
'you return a Component instead of <Component /> from render. ' +
|
||||
'you return Foo instead of <Foo /> from render. ' +
|
||||
'Or maybe you meant to call this function rather than return it.\n' +
|
||||
' <span>{Foo}</span>\n' +
|
||||
' in span (at **)\n' +
|
||||
' in div (at **)\n' +
|
||||
' in Foo (at **)',
|
||||
@@ -730,13 +733,15 @@ describe('ReactComponent', () => {
|
||||
});
|
||||
}).toErrorDev([
|
||||
'Warning: Functions are not valid as a React child. This may happen if ' +
|
||||
'you return a Component instead of <Component /> from render. ' +
|
||||
'you return Foo instead of <Foo /> from render. ' +
|
||||
'Or maybe you meant to call this function rather than return it.\n' +
|
||||
' <div>{Foo}</div>\n' +
|
||||
' in div (at **)\n' +
|
||||
' in Foo (at **)',
|
||||
'Warning: Functions are not valid as a React child. This may happen if ' +
|
||||
'you return a Component instead of <Component /> from render. ' +
|
||||
'you return Foo instead of <Foo /> from render. ' +
|
||||
'Or maybe you meant to call this function rather than return it.\n' +
|
||||
' <span>{Foo}</span>\n' +
|
||||
' in span (at **)\n' +
|
||||
' in div (at **)\n' +
|
||||
' in Foo (at **)',
|
||||
|
||||
+17
-2
@@ -487,8 +487,23 @@ describe('ReactDOMRoot', () => {
|
||||
});
|
||||
}).toErrorDev(
|
||||
'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.',
|
||||
'This may happen if you return Component instead of <Component /> from render. ' +
|
||||
'Or maybe you meant to call this function rather than return it.\n' +
|
||||
' root.render(Component)',
|
||||
{withoutStack: true},
|
||||
);
|
||||
});
|
||||
|
||||
it('warns when given a symbol', () => {
|
||||
const root = ReactDOMClient.createRoot(document.createElement('div'));
|
||||
|
||||
expect(() => {
|
||||
ReactDOM.flushSync(() => {
|
||||
root.render(Symbol('foo'));
|
||||
});
|
||||
}).toErrorDev(
|
||||
'Symbols are not valid as a React child.\n' +
|
||||
' root.render(Symbol(foo))',
|
||||
{withoutStack: true},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -71,8 +71,9 @@ describe('ReactMount', () => {
|
||||
|
||||
expect(() => ReactTestUtils.renderIntoDocument(Component)).toErrorDev(
|
||||
'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.',
|
||||
'This may happen if you return Component instead of <Component /> from render. ' +
|
||||
'Or maybe you meant to call this function rather than return it.\n' +
|
||||
' root.render(Component)',
|
||||
{withoutStack: true},
|
||||
);
|
||||
});
|
||||
|
||||
+82
-14
@@ -33,7 +33,13 @@ import {
|
||||
REACT_LAZY_TYPE,
|
||||
REACT_CONTEXT_TYPE,
|
||||
} from 'shared/ReactSymbols';
|
||||
import {ClassComponent, HostText, HostPortal, Fragment} from './ReactWorkTags';
|
||||
import {
|
||||
ClassComponent,
|
||||
HostRoot,
|
||||
HostText,
|
||||
HostPortal,
|
||||
Fragment,
|
||||
} from './ReactWorkTags';
|
||||
import isArray from 'shared/isArray';
|
||||
import {checkPropStringCoercion} from 'shared/CheckStringCoercion';
|
||||
|
||||
@@ -79,6 +85,7 @@ let didWarnAboutGenerators;
|
||||
let didWarnAboutStringRefs;
|
||||
let ownerHasKeyUseWarning;
|
||||
let ownerHasFunctionTypeWarning;
|
||||
let ownerHasSymbolTypeWarning;
|
||||
let warnForMissingKey = (child: mixed, returnFiber: Fiber) => {};
|
||||
|
||||
if (__DEV__) {
|
||||
@@ -93,6 +100,7 @@ if (__DEV__) {
|
||||
*/
|
||||
ownerHasKeyUseWarning = ({}: {[string]: boolean});
|
||||
ownerHasFunctionTypeWarning = ({}: {[string]: boolean});
|
||||
ownerHasSymbolTypeWarning = ({}: {[string]: boolean});
|
||||
|
||||
warnForMissingKey = (child: mixed, returnFiber: Fiber) => {
|
||||
if (child === null || typeof child !== 'object') {
|
||||
@@ -267,20 +275,68 @@ function throwOnInvalidObjectType(returnFiber: Fiber, newChild: Object) {
|
||||
);
|
||||
}
|
||||
|
||||
function warnOnFunctionType(returnFiber: Fiber) {
|
||||
function warnOnFunctionType(returnFiber: Fiber, invalidChild: Function) {
|
||||
if (__DEV__) {
|
||||
const componentName = getComponentNameFromFiber(returnFiber) || 'Component';
|
||||
const parentName = getComponentNameFromFiber(returnFiber) || 'Component';
|
||||
|
||||
if (ownerHasFunctionTypeWarning[componentName]) {
|
||||
if (ownerHasFunctionTypeWarning[parentName]) {
|
||||
return;
|
||||
}
|
||||
ownerHasFunctionTypeWarning[componentName] = true;
|
||||
ownerHasFunctionTypeWarning[parentName] = true;
|
||||
|
||||
console.error(
|
||||
'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.',
|
||||
);
|
||||
const name = invalidChild.displayName || invalidChild.name || 'Component';
|
||||
|
||||
if (returnFiber.tag === HostRoot) {
|
||||
console.error(
|
||||
'Functions are not valid as a React child. This may happen if ' +
|
||||
'you return %s instead of <%s /> from render. ' +
|
||||
'Or maybe you meant to call this function rather than return it.\n' +
|
||||
' root.render(%s)',
|
||||
name,
|
||||
name,
|
||||
name,
|
||||
);
|
||||
} else {
|
||||
console.error(
|
||||
'Functions are not valid as a React child. This may happen if ' +
|
||||
'you return %s instead of <%s /> from render. ' +
|
||||
'Or maybe you meant to call this function rather than return it.\n' +
|
||||
' <%s>{%s}</%s>',
|
||||
name,
|
||||
name,
|
||||
parentName,
|
||||
name,
|
||||
parentName,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function warnOnSymbolType(returnFiber: Fiber, invalidChild: symbol) {
|
||||
if (__DEV__) {
|
||||
const parentName = getComponentNameFromFiber(returnFiber) || 'Component';
|
||||
|
||||
if (ownerHasSymbolTypeWarning[parentName]) {
|
||||
return;
|
||||
}
|
||||
ownerHasSymbolTypeWarning[parentName] = true;
|
||||
|
||||
// eslint-disable-next-line react-internal/safe-string-coercion
|
||||
const name = String(invalidChild);
|
||||
|
||||
if (returnFiber.tag === HostRoot) {
|
||||
console.error(
|
||||
'Symbols are not valid as a React child.\n' + ' root.render(%s)',
|
||||
name,
|
||||
);
|
||||
} else {
|
||||
console.error(
|
||||
'Symbols are not valid as a React child.\n' + ' <%s>%s</%s>',
|
||||
parentName,
|
||||
name,
|
||||
parentName,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,7 +712,10 @@ function createChildReconciler(
|
||||
|
||||
if (__DEV__) {
|
||||
if (typeof newChild === 'function') {
|
||||
warnOnFunctionType(returnFiber);
|
||||
warnOnFunctionType(returnFiber, newChild);
|
||||
}
|
||||
if (typeof newChild === 'symbol') {
|
||||
warnOnSymbolType(returnFiber, newChild);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -778,7 +837,10 @@ function createChildReconciler(
|
||||
|
||||
if (__DEV__) {
|
||||
if (typeof newChild === 'function') {
|
||||
warnOnFunctionType(returnFiber);
|
||||
warnOnFunctionType(returnFiber, newChild);
|
||||
}
|
||||
if (typeof newChild === 'symbol') {
|
||||
warnOnSymbolType(returnFiber, newChild);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -894,7 +956,10 @@ function createChildReconciler(
|
||||
|
||||
if (__DEV__) {
|
||||
if (typeof newChild === 'function') {
|
||||
warnOnFunctionType(returnFiber);
|
||||
warnOnFunctionType(returnFiber, newChild);
|
||||
}
|
||||
if (typeof newChild === 'symbol') {
|
||||
warnOnSymbolType(returnFiber, newChild);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1621,7 +1686,10 @@ function createChildReconciler(
|
||||
|
||||
if (__DEV__) {
|
||||
if (typeof newChild === 'function') {
|
||||
warnOnFunctionType(returnFiber);
|
||||
warnOnFunctionType(returnFiber, newChild);
|
||||
}
|
||||
if (typeof newChild === 'symbol') {
|
||||
warnOnSymbolType(returnFiber, newChild);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+25
-5
@@ -2137,6 +2137,27 @@ function validateIterable(iterable, iteratorFn: Function): void {
|
||||
}
|
||||
}
|
||||
|
||||
function warnOnFunctionType(invalidChild: Function) {
|
||||
if (__DEV__) {
|
||||
const name = invalidChild.displayName || invalidChild.name || 'Component';
|
||||
console.error(
|
||||
'Functions are not valid as a React child. This may happen if ' +
|
||||
'you return %s instead of <%s /> from render. ' +
|
||||
'Or maybe you meant to call this function rather than return it.',
|
||||
name,
|
||||
name,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function warnOnSymbolType(invalidChild: symbol) {
|
||||
if (__DEV__) {
|
||||
// eslint-disable-next-line react-internal/safe-string-coercion
|
||||
const name = String(invalidChild);
|
||||
console.error('Symbols are not valid as a React child.\n' + ' %s', name);
|
||||
}
|
||||
}
|
||||
|
||||
// This function by it self renders a node and consumes the task by mutating it
|
||||
// to update the current execution state.
|
||||
function renderNodeDestructive(
|
||||
@@ -2329,11 +2350,10 @@ function renderNodeDestructive(
|
||||
|
||||
if (__DEV__) {
|
||||
if (typeof node === 'function') {
|
||||
console.error(
|
||||
'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.',
|
||||
);
|
||||
warnOnFunctionType(node);
|
||||
}
|
||||
if (typeof node === 'symbol') {
|
||||
warnOnSymbolType(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user