React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) 但得到:对象

React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object

预计

我应该可以导出我的 App 组件文件并将其导入我的 index.js。

结果

我收到以下错误

React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object


我的index.js

const React = require('react');
const ReactDOM = require('react-dom');
const App = require('./components/App');
require('./index.css');

ReactDOM.render(
    <App />,
    document.getElementById('app')
);

然后在我的components/App.js

const React = require('react');

export default class App extends React.Component {
    render() {
        return (
            <div>
                Hell World! Wasabi Sauce!
            </div>
        );
    }
}

// module.exports = App;

如果我取消注释 module.exports = App; 它会起作用,但我正在尝试使用导出语法。让我发疯的是在另一个项目中我在这里做完全相同的事情并且工作正常:(

您遇到的问题是由于混合了两种不同的模块系统引起的,这两种模块系统的方式不同 resolved and implemented. CommonJS modules are dynamic and contrary to that ES6 modules 可以进行静态分析。

Babel transpile ES6 modules to CommonJS as for now because native support is not ready yet 这样的工具。但是,存在细微差别。 通过使用 default export (exports default) 转译器发出一个带有 { default } 属性 的 CommonJS 模块,因为在 ES6 模块中可以命名和默认导出。以下示例是完全有效的 ES6 模块:

export default class Test1 { }
export class Test2 { }

这将在转译后生成 { default, Test2 } CommonJS 模块,并通过使用 require 获得该对象作为 return 值。

为了在 CommonJS 中导入 ES6 模块的默认导出,由于上述原因,您必须使用 require(module).default 语法。


正在调试React.createElement:类型无效错误

当 React 在导入的模块出现问题时尝试渲染组件时,此错误非常常见。大多数情况下,这是由于模块中缺少 export 或路径问题(相对路径是某种笑话)造成的,如果没有适当的工具,这可能会导致严重的问题。

在这种情况下,React 无法呈现通用对象 {__esModule: true, default: function},只是抛出了一个错误。 使用 require 时,有可能只打印出所需的模块以查看其内容,这可能有助于调试问题。


附带说明一下,除非您确实需要,否则请不要将 CommonJS 模块与 ES6 模块混合使用。 import/export 语法是为 ES6 模块保留的。使用 CommonJS 模块时,只需使用 module.exports 并使用 require 导入它们。将来,大多数开发人员将使用标准模块格式。在那之前,将它们混合在一起时要小心。

经常..

...就这么简单:

const MyModule = require('./MyModule');

const {MyModule} = require('./MyModule');

ES6 模块令人困惑。如果我们将它们与 NodeJS commonJS 模块模式混合使用,将会更加混乱 ;) ,

如果您使用前端代码,我建议使用一种单一样式,最好是 ES6 模块。 我写了一个示例应用程序来更好地理解它。

https://github.com/Sutikshan/es-bits/tree/master/modules

我遇到了同样的问题, 我做了这个技巧,对我有用,

你只需要把export放在class App,

之前
export class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <p>
            Edit <code>src/App.js</code> and save to reload.
          </p>
          <a
            className="App-link"
            href="https://reactjs.org"
            target="_blank"
            rel="noopener noreferrer"
          >
            Learn React
          </a>
        </header>
      </div>
    );
  }
}

export default App;

您还可以检查您正在使用的路由器, 我用过这个作品,

npm install react-router-dom@next --save

以防万一其他人 运行 也参与其中...
我遇到了同样的问题,但仅当 运行 宁我的 jest 测试代码时。我遇到了同样的上述错误:

React.createElement: type is invalid — expected a string (for built-in components) or a class/function (for composite components) but got: object

如果您的项目恰好在使用打字稿,但您正在使用 jest 测试(它在内部混合使用模块系统 - 包括 CommonJS require 语法),您仍然会遇到此错误如果您使用

,则使用 jest 进行测试
import React from 'react';

子组件中的语法而不是打字稿变体:

import * as React from 'react';

这是一个奇怪的错误并且很难发现,因为应用可能 运行 可以使用任何一种导入方法,但是 jest 主要组件的测试可能会失败,直到子组件更新为使用第二个反应语法(同样,对于那些使用带有 jest 测试的打字稿的人)。

对我来说这是循环依赖的问题。

//simplistic example

//a.js
import { foo } from './b.js'
export const bar = foo

//b.js
import { bar } from './a.js'
export const foo = bar