diff --git a/docs/warnings/invalid-element-type.md b/docs/warnings/invalid-element-type.md new file mode 100644 index 0000000000000..efcda12a098a8 --- /dev/null +++ b/docs/warnings/invalid-element-type.md @@ -0,0 +1,91 @@ +--- +title: Invalid Element Type Warning +layout: single +permalink: warnings/invalid-element-type.html +--- + +You probably came here because your code is trying to create a ReactElement with an invalid type using JSX or the `React.createElement` API. This usually happens when you have an invalid import statement. + +`React.createElement` requires an argument of type `string` (e.g. 'div', 'span'), or a `ReactClass`/`React.Component`. It cannot be of type `number`, `boolean`, `undefined` or `null`. See the documentation of this API: [https://facebook.github.io/react/docs/top-level-api.html](https://facebook.github.io/react/docs/top-level-api.html) + +The following common examples will trigger this error: + +### Invalid types + +Ensure that your component is not of the following types: undefined, boolean, number or null. + +`Components.js` + +```js +let Foo, Bar; + +if (false) { + Foo = () =>
; +} + +Bar = React.createElement(42); +// The following types are invalid, too. +// Bar = 42; +// Bar = null; +// Bar = undefined; +// Bar = true; + +export { Foo, Bar }; // Foo is undefined and Bar is an invalid element. +``` + +`App.js` + +```js +import { Foo, Bar } from './Components' + +class ReactApp extends Component { + render() { + return ; // or return + } +} +``` + +### Invalid member imports + +This happens when attempting to import a member as a default member, or importing a default member as a member. + +`Components.js` + +```js +export const Foo = () => { return
} +``` + +`App.js` + +```js +import Foo from './Components' // wrong! +// correct: import { Foo } from './Components'; + +class ReactApp extends Component { + render() { + return ; + } +} +``` + +### Invalid or missing export + +Check that the component is exported properly with the keyword `export`. + +`Components.js` + +```js +const Foo = () => { return
} // Foo needs to be exported +``` + +`App.js` + +```js +import { Foo } from './Components' // Foo is undefined + +class ReactApp extends Component { + render() { + return ; + } +} +``` diff --git a/src/isomorphic/classic/element/ReactElementValidator.js b/src/isomorphic/classic/element/ReactElementValidator.js index a899654153b48..6e95d23508250 100644 --- a/src/isomorphic/classic/element/ReactElementValidator.js +++ b/src/isomorphic/classic/element/ReactElementValidator.js @@ -180,21 +180,37 @@ function validatePropTypes(element) { } } +function warnInvalidType(inputValue) { + if (inputValue === undefined) { + warning( + false, + 'React.createElement: undefined is an invalid element type. ' + + 'Did you mistype an import or forget to export your component? ' + + 'It should be a string (for DOM elements), component ' + + 'class or function (for user-defined components).' + + '%s See https://fb.me/react-invalid-element-type for more information.', + getDeclarationErrorAddendum() + ); + } else { + warning( + false, + 'React.createElement: %s is an invalid element type. ' + + 'It should be a string (for DOM elements), component ' + + 'class or function (for user-defined components).' + + '%s See https://fb.me/react-invalid-element-type for more information.', + inputValue, + getDeclarationErrorAddendum() + ); + } +} + var ReactElementValidator = { createElement: function(type, props, children) { var validType = typeof type === 'string' || typeof type === 'function' || (type !== null && typeof type === 'object'); - // We warn in this case but don't throw. We expect the element creation to - // succeed and there will likely be errors in render. if (!validType) { - warning( - false, - 'React.createElement: type should not be null, undefined, boolean, or ' + - 'number. It should be a string (for DOM elements) or a ReactClass ' + - '(for composite components).%s', - getDeclarationErrorAddendum() - ); + warnInvalidType(type); } var element = ReactElement.createElement.apply(this, arguments); diff --git a/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js b/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js index d646e1ae98434..92b003bba69a6 100644 --- a/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js +++ b/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js @@ -297,24 +297,29 @@ describe('ReactElementValidator', function() { React.createElement(123); expect(console.error.calls.count()).toBe(4); expect(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: React.createElement: type should not be null, undefined, ' + - 'boolean, or number. It should be a string (for DOM elements) or a ' + - 'ReactClass (for composite components).' + 'Warning: React.createElement: undefined is an invalid element type. ' + + 'Did you mistype an import or forget to export your component? ' + + 'It should be a string (for DOM elements), component class or function ' + + '(for user-defined components). ' + + 'See https://fb.me/react-invalid-element-type for more information.' ); expect(console.error.calls.argsFor(1)[0]).toBe( - 'Warning: React.createElement: type should not be null, undefined, ' + - 'boolean, or number. It should be a string (for DOM elements) or a ' + - 'ReactClass (for composite components).' + 'Warning: React.createElement: null is an invalid element type. ' + + 'It should be a string (for DOM elements), component class or function ' + + '(for user-defined components). ' + + 'See https://fb.me/react-invalid-element-type for more information.' ); expect(console.error.calls.argsFor(2)[0]).toBe( - 'Warning: React.createElement: type should not be null, undefined, ' + - 'boolean, or number. It should be a string (for DOM elements) or a ' + - 'ReactClass (for composite components).' + 'Warning: React.createElement: true is an invalid element type. ' + + 'It should be a string (for DOM elements), component class or function ' + + '(for user-defined components). ' + + 'See https://fb.me/react-invalid-element-type for more information.' ); expect(console.error.calls.argsFor(3)[0]).toBe( - 'Warning: React.createElement: type should not be null, undefined, ' + - 'boolean, or number. It should be a string (for DOM elements) or a ' + - 'ReactClass (for composite components).' + 'Warning: React.createElement: 123 is an invalid element type. ' + + 'It should be a string (for DOM elements), component class or function ' + + '(for user-defined components). ' + + 'See https://fb.me/react-invalid-element-type for more information.' ); React.createElement('div'); expect(console.error.calls.count()).toBe(4); @@ -336,10 +341,10 @@ describe('ReactElementValidator', function() { ); expect(console.error.calls.count()).toBe(1); expect(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: React.createElement: type should not be null, undefined, ' + - 'boolean, or number. It should be a string (for DOM elements) or a ' + - 'ReactClass (for composite components). Check the render method of ' + - '`ParentComp`.' + 'Warning: React.createElement: null is an invalid element type. ' + + 'It should be a string (for DOM elements), component class or function ' + + '(for user-defined components). Check the render method of `ParentComp`. ' + + 'See https://fb.me/react-invalid-element-type for more information.' ); }); @@ -537,9 +542,11 @@ describe('ReactElementValidator', function() { void {[
]}; expect(console.error.calls.count()).toBe(1); expect(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: React.createElement: type should not be null, undefined, ' + - 'boolean, or number. It should be a string (for DOM elements) or a ' + - 'ReactClass (for composite components).' + 'Warning: React.createElement: undefined is an invalid element type. ' + + 'Did you mistype an import or forget to export your component? ' + + 'It should be a string (for DOM elements), component class or function ' + + '(for user-defined components). ' + + 'See https://fb.me/react-invalid-element-type for more information.' ); }); diff --git a/src/isomorphic/modern/element/__tests__/ReactJSXElementValidator-test.js b/src/isomorphic/modern/element/__tests__/ReactJSXElementValidator-test.js index 4f5417e08413d..18c5eea3d1d66 100644 --- a/src/isomorphic/modern/element/__tests__/ReactJSXElementValidator-test.js +++ b/src/isomorphic/modern/element/__tests__/ReactJSXElementValidator-test.js @@ -219,20 +219,25 @@ describe('ReactJSXElementValidator', function() { void ; expect(console.error.calls.count()).toBe(4); expect(console.error.calls.argsFor(0)[0]).toContain( - 'type should not be null, undefined, boolean, or number. It should be ' + - 'a string (for DOM elements) or a ReactClass (for composite components).' + 'undefined is an invalid element type. ' + + 'Did you mistype an import or forget to export your component? ' + + 'It should be a string (for DOM elements), component class or function ' + + '(for user-defined components). ' ); expect(console.error.calls.argsFor(1)[0]).toContain( - 'type should not be null, undefined, boolean, or number. It should be ' + - 'a string (for DOM elements) or a ReactClass (for composite components).' + 'null is an invalid element type. ' + + 'It should be a string (for DOM elements), component class or function ' + + '(for user-defined components). ' ); expect(console.error.calls.argsFor(2)[0]).toContain( - 'type should not be null, undefined, boolean, or number. It should be ' + - 'a string (for DOM elements) or a ReactClass (for composite components).' + 'true is an invalid element type. ' + + 'It should be a string (for DOM elements), component class or function ' + + '(for user-defined components). ' ); expect(console.error.calls.argsFor(3)[0]).toContain( - 'type should not be null, undefined, boolean, or number. It should be ' + - 'a string (for DOM elements) or a ReactClass (for composite components).' + '123 is an invalid element type. ' + + 'It should be a string (for DOM elements), component class or function ' + + '(for user-defined components). ' ); void
; expect(console.error.calls.count()).toBe(4);