React.createElement: 类型无效——需要一个字符串(对于内置组件)或一个类/函数(对于复合组件)但得到:对象

IT技术 javascript reactjs ecmascript-6 export commonjs
2021-03-29 20:33:36

预期的

我应该能够导出我的 App 组件文件并将其导入到我的 index.js 中。

结果

我收到以下错误

React.createElement: 类型无效——需要一个字符串(对于内置组件)或一个类/函数(对于复合组件)但得到:对象


我的 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;它会起作用,但我正在尝试使用导出语法。让我发疯的是在另一个项目中我在这里做完全相同的事情并且它工作正常:(

6个回答

您遇到的问题是由两种不同的module系统混合引起的,它们的解决和实施方式各不相同CommonJS module是动态的,与ES6 module是静态可分析的相反

Babel这样的工具目前将 ES6 module转换为 CommonJS,因为原生支持还没有准备好但是,存在细微的差异。通过使用默认导出(exports default,转译器发出一个带有{ default }属性的 CommonJS module,因为在 ES6 module中可以命名和默认导出。以下示例是完全有效的 ES6 module:

export default class Test1 { }
export class Test2 { }

这将{ default, Test2 }在转译后产生CommonJS module,并通过使用require该对象作为返回值。

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


调试 React.createElement: type is invalid 错误

当导入的module出现问题时,React 尝试渲染组件时,此错误非常常见。大多数情况下,这是由exportmodule中缺失或路径问题(相对路径是某种笑话)引起的,如果没有适当的工具,这可能会导致严重的头发拉扯。

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


作为旁注,除非您确实需要,否则请不要将 CommonJS module与 ES6 module混合使用。import/export语法是为 ES6 module保留的。使用 CommonJS module时,只需要 usemodule.exports和 userequire来导入它们。将来,大多数开发人员将使用标准module格式。在此之前,将它们混合在一起时要小心。

常常..

...它很简单:

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

对比

const {MyModule} = require('./MyModule');
非常感谢兄弟,我使用“react-data-components”module对数据进行排序、过滤和页面导航。以前我导入 like ==>import DataTable from 'react-data-components'; 然后我得到了这个错误。但是添加花括号后它工作正常。==> 从 'react-data-components' 导入 {DataTable};我几乎浪费了3个小时的时间。再次谢谢老哥
2021-05-29 20:33:36
用大括号包裹有什么作用?我和 OP 有同样的问题,但 { } 有帮助
2021-05-29 20:33:36
2021-05-30 20:33:36

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

你只需要在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 — 期望字符串(对于内置组件)或类/函数(对于复合组件)但得到:对象

如果您的项目碰巧使用typescript,但您正在使用jest测试(它在内部使用混合module系统 - 包括 CommonJSrequire语法),jest如果您使用

import React from 'react';

子组件中的语法而不是 typescript 变体:

import * as React from 'react';

这是一个奇怪的错误并且可能很难捕捉到,因为应用程序可能使用任何一种导入方法都可以正常运行,但是jest在子组件更新为使用第二个 react 语法之前,主组件测试可能会失败(同样,对于那些使用带jest测试的typescript)。

ES6 module令人困惑。如果我们将它们与 NodeJS 的 commonJS module模式混合在一起,会更加混乱 ;) ,

如果您在前端代码中工作,我建议使用单一样式,最好使用 ES6 module。我写了一个示例应用程序来更好地理解它。

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