React.createElement:type无效 - 期望一个字符串

时间:2017-03-15 14:57:12

标签: reactjs react-router react-hot-loader

试图让react-router(v4.0.0)和react-hot-loader(3.0.0-beta.6)很好地播放,但是在浏览器控制台中出现以下错误:

  

警告:React.createElement:type无效 - 需要一个字符串   (对于内置组件)或类/函数(对于复合   组件)但得到:未定义。你可能忘了导出你的   来自其定义的文件中的组件。

index.js:

import React from 'react';
import ReactDom from 'react-dom';
import routes from './routes.js';
require('jquery');
import 'bootstrap/dist/css/bootstrap.min.css';
import 'bootstrap/dist/js/bootstrap.min.js';
import './css/main.css';

const renderApp = (appRoutes) => {
    ReactDom.render(appRoutes, document.getElementById('root'));
};

renderApp( routes() );

routes.js:

import React from 'react';
import { AppContainer } from 'react-hot-loader';
import { Router, Route, browserHistory, IndexRoute } from 'react-router';
import store from './store/store.js';
import { Provider } from 'react-redux';
import App from './containers/App.jsx';
import Products from './containers/shop/Products.jsx';
import Basket from './containers/shop/Basket.jsx';

const routes = () => (

    <AppContainer>
        <Provider store={store}>
            <Router history={browserHistory}>
                <Route path="/" component={App}>
                    <IndexRoute component={Products} />
                    <Route path="/basket" component={Basket} />
                </Route>
            </Router>
        </Provider>
    </AppContainer>

);

export default routes;

32 个答案:

答案 0 :(得分:67)

大多数情况下,这是因为您没有正确导出/导入。

常见错误:

// File: LeComponent.js
export class LeComponent extends React.Component { ... }

// File: App.js
import LeComponent from './LeComponent';

// no "default" export, should be  export default class LeComponent

有几种方法可能是错误的,但这种错误是因为每次都有60%的时间导入/导出错误。

修改

通常,您获取堆栈跟踪,该堆栈跟踪指示发生故障的位置的大致位置。这通常紧跟在您原始问题中的消息之后。

如果没有显示,可能值得调查原因(可能是您缺少的构建设置)。无论如何,如果它没有显示,唯一的行动方案是缩小,其中导出/导入失败。

可悲的是,没有堆栈跟踪的唯一方法就是手动删除每个模块/子模块,直到你不再得到错误,然后按照你的方式备份堆栈。

修改2

通过评论,这确实是一个导入问题,特别是导入一个不存在的模块

答案 1 :(得分:9)

试试这个

npm i react-router-dom@next
App.js

中的

import { BrowserRouter as Router, Route } from 'react-router-dom'

const Home = () => <h1>Home</h1>

const App = () =>(
  <Router>
    <Route path="/" component={Home} />
  </Router>
)

export default App;

答案 2 :(得分:5)

我也遇到了这个错误。

我正在使用:

import BrowserRouter from 'react-router-dom';

修复就是这样做,而不是:

import { BrowserRouter } from 'react-router-dom';

答案 3 :(得分:4)

当我将css文件添加到与组件文件相同的文件夹时,我遇到了这个问题。

我的导入声明是:

import MyComponent from '../MyComponent'

当只有一个文件MyComponent.jsx时,这很好。 (我在一个例子中看到了这种格式并尝试了一下,然后忘记了我已经完成了它)

当我将MyComponent.scss添加到同一文件夹时,导入失败。也许JavaScript加载了.scss文件,因此没有错误。

我的结论:即使只有一个文件,也要指定文件扩展名,以防以后再添加另一个文件。

答案 4 :(得分:4)

组件数组

发生此错误的一种常见方法是使用组件数组,并使用位置索引从数组中选择要呈现的组件。我多次看到这样的代码:

const checkoutSteps = [Address, Shipment, Payment]

export const Checkout = ({step}) => {

  const ToRender = checkoutSteps[step]

  return (
    <ToRender />
  )
}

这不是必需的错误代码,但是如果您使用错误的索引(例如-13)调用它,则ToRender组件将是{{1 }},引发undefined错误:

React.createElement: type is invalid...

合理的解决方案

您应该使用更明确的方法 保护 自己和同事免受此难以调试的代码的使用,避免使用幻数并使用道具类型:

<Checkout step={0} /> // <Address />
<Checkout step={1} /> // <Shipment />
<Checkout step={2} /> // <Payment />
<Checkout step={3} /> // undefined
<Checkout step={-1} /> // undefined

您的代码将如下所示:

const checkoutSteps = {
  address: Address,
  shipment Shipment,
  payment: Payment
}

const propTypes = {
  step: PropTypes.oneOf(['address', 'shipment', 'payment']),
}

/* TIP: easier to maintain
const propTypes = {
  step: PropTypes.oneOf(Object.keys(checkoutSteps)),
}
*/

const Checkout = ({step}) => {

  const ToRender = checkoutSteps[step]

  return (
    <ToRender />
  )
}

Checkout.propTypes = propTypes

export default Checkout

这种方法的优点

  • 代码更具显性明确性,您可以清楚地看到要呈现的内容
  • 您不需要记住数字及其隐藏的含义(// OK <Checkout step="address" /> // <Address /> <Checkout step="shipment" /> // <Shipment /> <Checkout step="payment" /> // <Payment /> // Errors <Checkout step="wrongstep" /> // explicit error "step must be one of..." <Checkout step={3} /> // explicit error (same as above) <Checkout step={myWrongVar} /> // explicit error (same as above) 用于地址, 2 用于...)
  • 错误也是明确的
  • 您的同伴们不头痛:)

答案 5 :(得分:1)

就我而言,我忘了在index.js文件中导入和导出渲染器调用的(新)元素。

答案 6 :(得分:1)

我错过了React Fragment


function Bar({ children }) {

  return (
    <div>
     {children}
    </div>
  );
}

function Foo() {
  return (
    <Bar>
      <Baz/>
      <Qux/>
    </Bar>
  );
}

上面的代码引发上面的错误。但这可以解决此问题:

<Bar>
  <>
    <Baz/>
    <Qux/>
  </>
</Bar>

答案 7 :(得分:1)

当我在渲染/返回语句中引用错误时,就发生了这个问题。 (指向不存在的类)。 还要检查您的退货声明代码是否有错误的引用。

答案 8 :(得分:1)

这意味着您的导入/导出不正确

  • 检查新添加的import/exports
  • 就我而言,我不必要使用大括号。删除这些大括号后,问题自动得到解决。
import { OverlayTrigger } from 'react-bootstrap/OverlayTrigger';

答案 9 :(得分:1)

简而言之,发生了以下事情:

render() {
    return (
        <MyComponent /> // MyComponent is undefined.
    );
}

它不一定与某些不正确的导入或导出有关:

render() {
    // MyComponent may be undefined here, for example.
    const MyComponent = this.wizards[this.currentStep];

    return (
        <MyComponent />
    );
}

答案 10 :(得分:1)

我也收到了这个错误。

我正在使用:

import ReactDOM from 'react-dom';

Fix 正在这样做:

import {ReactDOM} from 'react-dom';

答案 11 :(得分:1)

我缺少的是我正在使用

import { Router, Route, browserHistory, IndexRoute } from 'react-router';

代替或正确答案应该是:

import { BrowserRouter as Router, Route } from 'react-router-dom';

当然你需要添加npm包 react-router-dom

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

答案 12 :(得分:0)

就我而言,我添加了相同的自定义组件作为道具而不是实际道具

   import AddAddress from '../../components/Manager/AddAddress';
    
    class Add extends React.PureComponent {
      render() {
        const {
          history,
          addressFormData,
          formErrors,
          addressChange,
          addAddress,
          isDefault,
          defaultChange
        } = this.props;
    

错误:

    return (
        <AddAddress
          addressFormData={addressFormData}
          formErrors={formErrors}
          addressChange={addressChange}
          addAddress={AddAddress} // here i have used the Component name as probs in same component itself instead of prob
          isDefault={isDefault}
          defaultChange={defaultChange}
        />
      </SubPage>

解决方案:

return (
    <AddAddress
      addressFormData={addressFormData}
      formErrors={formErrors}
      addressChange={addressChange}
      addAddress={addAddress} // removed the component name and give prob name
      isDefault={isDefault}
      defaultChange={defaultChange}
    />
  </SubPage>

答案 13 :(得分:0)

我遇到了完全相同的错误,请改为执行此操作:

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

答案 14 :(得分:0)

xxxxx.prototype = {
  dxxxx: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
};

您必须添加// eslint-disable-line react/forbid-prop-types,然后它才能正常工作!

答案 15 :(得分:0)

我正在开发的应用程序将反应组件的名称作为小部件配置存储在浏览器存储中。其中一些组件被删除,应用程序仍在尝试渲染它们。通过清除浏览器缓存,我能够解决我的问题。

答案 16 :(得分:0)

这不一定是与导入/导出有关的直接问题。就我而言,我正在将一个子元素呈现在一个父元素内,并且该子元素具有jsx元素/标签,该元素已使用但未导入。我导入了它,然后使用它解决了问题。因此问题出在子元素内部的jsx元素中,而不是子元素本身的导出。

答案 17 :(得分:0)

真的很简单。我开始编写React时遇到了这个问题,问题几乎总是因为import:

import React, { memo } from 'react';

您可以使用此方法来进行分解,因为react lib具有作为备忘录的属性,但是您不能使用这种方法来进行破坏

import { user } from 'assets/images/icons/Profile.svg';

因为它不是对象。

希望有帮助!

答案 18 :(得分:0)

这是一个必须调试的错误。正如许多次所说的,不正确的导入/导出会导致此错误,但是令人惊讶的是,我的情况是我的react-router-dom authentication setup中的一个小错误引起的:

错误设置:

const PrivateRoute = ({ component: Component, ...rest }) => (
    <Route
        {...rest}
        render={(props) => (token ? <Component {...props} /> : <Redirect to={{ pathname: "/login" }} />)}
    />
);

正确的设置:

const PrivateRoute = ({ component: Component, token, ...rest }) => (
    <Route
        {...rest}
        render={(props) => (token ? <Component {...props} /> : <Redirect to={{ pathname: "/login" }} />)}
    />
);

唯一的区别是我在token中解构了PrivateRoute component。顺便说一下,像这样的localstorage是从const token = localStorage.getItem("authUser");获得令牌的,因此,如果令牌不存在,我就知道该用户未被认证。这也会导致该错误。

答案 19 :(得分:0)

所以我遇到了这个问题,我能够以一种奇怪的方式修复它。我想我会把它扔掉,以防其他人遇到它并且变得绝望。

我有一个条件渲染的 react 元素,它只在状态对象大于零时才渲染。在渲染函数中 - 当三元运算符被证明为真时,我收到了这篇文章所涉及的错误。我在渲染函数中使用了 <React.Fragment> - 这是我通常将子项分组的方式,而不是使用较新的简短语法 (<> and </>) 的较新方式。

但是,当我将 <React.Fragment> 更改为简短语法时 - 反应元素正确呈现并且错误停止出现。我查看了 Facebook 的 React-Fragment 文档,我没有看到任何理由相信两者之间存在巨大差异会导致这种情况。无论如何,下面是两个简化的代码片段供您查看。第一个演示了产生错误的代码,第二个演示了解决问题的代码。最底层是组件本身的render函数。

希望有人觉得这有帮助。

代码示例 1 - 错误 条件渲染的 React 元素


  renderTimeFields = () => {
    return (
      <React.Fragment>
        <div className="align-left">
                <div className="input-row">
                  <label>Date: </label>
                  <input type="date" className="date" name="date" min={new Date().toISOString().split('T')[0]} required/>
                </div>
              </div>
              <div className="align-left sendOn-row">
                <div className="input-row">
                  <label>Time: </label>
                  <input type="time" className="time" name="time" required/>
                </div>
              </div>
      </React.Fragment>
    );
  }

代码示例 2 - 没有错误 条件渲染的 React 元素


  renderTimeFields = () => {
    return (
      <>
        <div className="align-left">
                <div className="input-row">
                  <label>Date: </label>
                  <input type="date" className="date" name="date" min={new Date().toISOString().split('T')[0]} required/>
                </div>
              </div>
              <div className="align-left sendOn-row">
                <div className="input-row">
                  <label>Time: </label>
                  <input type="time" className="time" name="time" required/>
                </div>
              </div>
      </>
    );
  }

组件内的渲染函数

render() {
<form>
...
{emailsInActiveScript > 1 ? this.renderTimeFields() : null}
</form>
etc...
}

答案 20 :(得分:0)

循环依赖也是此的原因之一。 [一般]

答案 21 :(得分:0)

我认为解决此错误时最重要的事情是,当您尝试实例化不存在的组件时,它就会显现出来。该组件不必导入。就我而言,我将组件作为属性传递。在进行一些重构后,我忘记更新其中一个调用以正确传递组件。不幸的是,由于JS不是静态类型的,所以没有捕获到我的错误,并且花了一些时间才弄清楚发生了什么。

要解决此错误,请在渲染组件之前检查组件,以确保它是您期望的组件类型。

答案 22 :(得分:0)

就我而言,尝试使用ContextApi时发生了错误。我误用了:

const MyContext = () => createContext()

但是它应该被定义为:

const MyContext = createContext()

我将其张贴在这里,以便将来因此类愚蠢错误而陷入困境的访客将有助于避免数小时的头痛,因为这不是由错误的进出口引起的。

答案 23 :(得分:0)

多数情况下,这表示导入/导出错误。但是请注意,不仅要确保堆栈跟踪中的引用文件本身已正确导出,而且还请确保此文件正确导入了其他组件。就我而言,错误是这样的:

import React from 'react';

// Note the .css at the end, this is the cause of the error!
import SeeminglyUnimportantComponent from './SeeminglyUnimportantComponent.css';

const component = (props) => (            
  <div>
    <SeeminglyUnimportantComponent />
    {/* ... component code here */}
  </div>    
);

export default component;

答案 24 :(得分:0)

如果在测试组件时出现此错误,请确保每个子组件在单独运行时都能正确呈现,如果您的一个子组件依赖于外部资源来呈现,请尝试使用jest或任何其他模拟lib对其进行模拟:

示例:

jest.mock('pathToChildComponent', () => 'mock-child-component')

答案 25 :(得分:0)

我遇到了这个错误,我的情况没有一个答案,这可能有助于谷歌搜索:

我定义的Proptype错误:

ids: PropTypes.array(PropTypes.string)

应该是:

ids: PropTypes.arrayOf(PropTypes.string)

VSCode和编译错误没有给我正确的提示。

答案 26 :(得分:0)

就我而言,我只需要从react-router-redux升级到react-router-redux@next。我假设它一定是某种兼容性问题。

答案 27 :(得分:0)

在我的例子中,创建组件和渲染的顺序很重要。我在创建之前渲染了组件。最好的方法是创建子组件,然后创建父组件,然后创建父组件。更改订单为我解决了问题。

答案 28 :(得分:0)

您需要了解named exportdefault export。见When should I use curly braces for ES6 import?

在我的情况下,我通过更改

来修复它
import Provider from 'react-redux'

import { Provider } from 'react-redux'

答案 29 :(得分:-1)

我只花了30分钟来尝试解决这个BASIC基本问题。

我的问题是我正在导入本机元素

例如import React, { Text, Image, Component } from 'react';

并尝试使用它们,这导致我收到此错误。

一旦我从<Text>切换到<p>,并且从<Image>切换到<img>,一切都会按预期进行。

答案 30 :(得分:-1)

// @flow

import React from 'react';
import { styleLocal } from './styles';
import {
  View,
  Text,
  TextInput,
  Image,
} from 'react-native';
import { TouchableOpacity } from 'react-native-gesture-handler';

export default React.forwardRef((props, ref) => {
const { onSeachClick, onChangeTextSearch , ...otherProps } = props;

  return (
        <View style={styleLocal.sectionStyle}>
        <TouchableOpacity onPress={onSeachClick}>
            <Image                              
                    source={require('../../assets/imgs/search.png')}
                    style={styleLocal.imageStyle} />
                </TouchableOpacity>
            <TextInput
                style={{ flex: 1, fontSize: 18 }}
                placeholder="Search Here"
                underlineColorAndroid="transparent"
                onChangeText={(text) => { onChangeTextSearch(text) }}
            />
        </View>
  );
});
 import IGPSSearch from '../../components/IGPSSearch';
<Search onSeachClick={onSeachClick} onChangeTextSearch= {onChangeTextSearch}> </Search>

答案 31 :(得分:-1)

修改

您正在使流程变得复杂。就这样做:

index.js:

import React from 'react';
import ReactDom from 'react-dom';
import routes from './routes.js';
require('jquery');
import 'bootstrap/dist/css/bootstrap.min.css';
import 'bootstrap/dist/js/bootstrap.min.js';
import './css/main.css';

ReactDom.render(<routes />, document.getElementById('root'));

routes.js:

import React from 'react';
import { AppContainer } from 'react-hot-loader';
import { Router, Route, browserHistory, IndexRoute } from 'react-router';
import store from './store/store.js';
import { Provider } from 'react-redux';
import App from './containers/App.jsx';
import Products from './containers/shop/Products.jsx';
import Basket from './containers/shop/Basket.jsx';

const routes =
    <AppContainer>
        <Provider store={store}>
            <Router history={browserHistory}>
                <Route path="/" component={App}>
                    <IndexRoute component={Products} />
                    <Route path="/basket" component={Basket} />
                </Route>
            </Router>
        </Provider>
    </AppContainer>;

export default routes;