Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React.createElement: type is invalid -- expected a string

Most of the time this is due to an incorrect export/import.

Common error:

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

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

Possible option:

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

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

There are a few ways it could be wrong, but that error is because of an import/export mismatch 60% of the time, everytime.

Edit

Typically you should get a stacktrace that indicates an approximate location of where the failure occurs. This generally follows straight after the message you have in your original question.

If it doesn't show, it might be worth investigating why (it might be a build setting that you're missing). Regardless, if it doesn't show, the only course of action is narrowing down where the export/import is failing.

Sadly, the only way to do it, without a stacktrace is to manually remove each module/submodule until you don't get the error anymore, then work your way back up the stack.

Edit 2

Via comments, it was indeed an import issue, specifically importing a module that didn't exist


I was getting this error as well.

I was using:

import BrowserRouter from 'react-router-dom';

Fix was doing this, instead:

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


Try this

npm i react-router-dom@next

in your 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;

Array of components

A common way to get this error is using an array of components, with a positional index used to select the component to render from the array. I saw a code like this many times:

const checkoutSteps = [Address, Shipment, Payment]

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

  const ToRender = checkoutSteps[step]

  return (
    <ToRender />
  )
}

This is not necessary bad code, but if you call it with a wrong index (eg -1, or 3 in this case), the ToRender component will be undefined, throwing the React.createElement: type is invalid... error:

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

A rational solution

You should protect yourself and your collegues from this hard-to-debug code using a more explicit approach, avoiding magic numbers and using PropTypes:

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

And your code will look like this:

// 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)

Benefits of this approach

  • code is more explicit, you can clearly see what you want to render
  • you don't need to remember the numbers and their hidden meaning (1 is for Address, 2 is for...)
  • errors are explicit too
  • no headache for your peers :)

You need to be aware of named export and default export. See When should I use curly braces for ES6 import?

In my case, I fixed it by changing from

import Provider from 'react-redux'

to

import { Provider } from 'react-redux'

I had this problem when I added a css file to the same folder as the component file.

My import statement was:

import MyComponent from '../MyComponent'

which was fine when there was only a single file, MyComponent.jsx. (I saw this format in an example and gave it a try, then forgot I'd done it)

When I added MyComponent.scss to the same folder, the import then failed. Maybe JavaScript loaded the .scss file instead, and so there was no error.

My conclusion: always specify the file extension even if there is only one file, in case you add another one later.


I was getting this error as well.

I was using:

import ReactDOM from 'react-dom';

Fix was doing this, instead:

import {ReactDOM} from 'react-dom';