React.createElement: type is invalid -- expected a string
Solution 1:
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
Solution 2:
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';
Solution 3:
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;
Solution 4:
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 :)