React: ‘Element type is invalid … check your render method’

Once you’ve seen this error once in your React app you’ll probably instantly recognize it and know exactly what this means:

Uncaught Error: Element type is invalid: expected a string 
(for built-in components) or a class/function (for composite 
components) but got: object. You likely forgot to export your 
component from the file it's defined in. Check the render 
method of `App`.

The key is “You likely forgot to export your component…” which was exactly the issue in my case.

If you have an ES6 style component this:

class App extends Component {
...
}

… check that you’ve exported it at the end of the source file with:

export default App;

Adding React Router to a React App

react-router is a routing library for React, that allows you to declare which components render based on url paths. It’s similar to ng-route and ui-router in AngularJS.

To get started, install react-router npm module:

npm install react-router --save

Full docs are here.

While working on converting an existing web app to React, I ran into a few issues getting my react-router usage working as I wanted.

Here’s my first attempt adding the Router declarations into an existing Container component that renders NavigationComponent – this Component renders a set of navigation links that are common across each of the pages:

<div>
    <NavigationComponent/>
    <Router history={hashHistory}>
        <Route path="/" component={Home}/>
        <IndexRoute component={Home} />
        <Route path="new" component={AddNew} />
        <Route path="search" component={Search} />
    </Router>
</div>

The first error I ran into was this:

Uncaught Error: <Link>s rendered outside of a router context cannot navigate.

Ok, this makes sense, so I need to move the NavigationComponent that renders my Links within <Router> :

<Router history={hashHistory}>
    <Route path="/" component={NavigationComponent}/>
    <IndexRoute component={Home} />
    <Route path="new" component={AddNew} />
    <Route path="search" component={Search} />
</Router>

Routes at the same level replace each other when rendered. To keep the navigation component rendered with the AddNew and Search as child sections of the nav area, nest the Routes as child elements:

<Router history={hashHistory}>
    <Route path="/" component={NavigationComponent}>
        <IndexRoute component={Home} />
        <Route path="new" component={AddNew} />
        <Route path="search" component={Search} />
    </Route>
</Router>

Now, for the NavigationComponent to render it’s child elements, you need to tell it to render:

{this.props.children}

So now this becomes:

render() {
    return (
        <div>
            <div>
                <nav className="navbar navbar-default" role="navigation">
                    <div className="navbar-header">
                        <Link className="navbar-brand" to="/">AddressBook</Link>
                    </div>

                    <div className="collapse navbar-collapse navbar-ex1-collapse">
                        <ul className="nav navbar-nav">
                            <li className="active"><Link to="search">Search</Link></li>
                            <li><Link to="new">New</Link></li>
                        </ul>
                    </div>
                </nav>
            </div>

            <div>
                {this.props.children}
            </div>
        </div>
    )
}

Here’s a good reference for getting started: https://medium.com/reactspeed/create-basic-navigation-components-using-react-router-475bc55a517f#.itkvn5st9

 

 

Comparing React with ES5 versus React with ES6

Learning React in 2016 seemed like it was stuck halfway transitioning from examples and tutorials using ES5 JavaScript, to the similar but different ES6 JavaScript syntax. If you haven’t done any JavaScript for a while (or at all), it was easy to get confused between the different styles. Even worse, you could easily spend some time reading an article before realizing that it was using ES5 or ES6 syntax and recognizing the differences (or not). As I was learning React, I’m sure I wasn’t the first to paste some ES5 style React syntax into a app using ES6 and get into a complete mess. Once you’ve got to the point of recognizing the differences then it becomes more obvious which is which, and becomes easier to spot an older (and possibly out of date) article with a newer, up to date article.

I like to build example apps to help me understand what’s going on with any new tech or framework, so thought it would be useful to build the same app twice, once using React with ES5 and then rebuild it with React and ES6 as a comparison.

Here’s a rundown of the differences and similarities (I’m sure there’s others too, but these are the ones I’m familiar with).

First up, the entry index.html for each app is mostly the same. The only difference with the ES5 version on the left is that I manually included the webpacked bundle.js, whereas this was done for me from the create-react-app scripts:

Next up, the first index.js to set up the root container component is almost identical. The only difference the JavaScript ES5 using the RequireJS module syntax, versus the ES6 style imports:

Now looking at the AppContainer component. React with ES5 on the left, and ES6 on the right:

Using React with ES5:

  • uses the React.createClass() api
  • defines component state using getInitialState()
  • exports the component as a module using ‘module.exports’

React with ES6:

  • uses the ES6 class
  • defines component state using this.state in the constructor()
  • exports the component as a module using ‘export default’

The render() function is similar in both.

CalculatorComponent – here you’ll notice some more significant differences:

React with ES5:

  • props are implicit
  • implicit binding of ‘this’ to functions

React with ES6:

  • props are passed into the component via the constructor()
  • explicit binding of ‘this’ to functions in the constructor, using this.functionname.bind(this)

And that’s it! Hope this is a useful reference if you’re looking for a side by side comparison. You can clone my example apps from github here: https://github.com/kevinhooke/ReactJavaScriptComparisons

As I’m still learning as I go, if I’ve misunderstood anything or got anything wrong, please leave a comment and let me know!

React: _registerComponent(…): Target container is not a DOM element

Using Webpack with React, it’s critical you import your bundle.js after any DOM elements in your page that you intend to reference. See this issue discussed in this SO question here.

For example:

<body>
<h2>React with ES5</h2>
 <script src="dist/bundle.js"></script>
 <div id="app"></div>
</body>

Importing bundle.js before a DIV element that you reference in your app will result in this error:

Uncaught Error: _registerComponent(...): Target container is not a DOM element.
    at invariant (bundle.js:839)
    at Object._renderNewRootComponent (bundle.js:20668)
    at Object._renderSubtreeIntoContainer (bundle.js:20758)
    at Object.render (bundle.js:20779)

Instead, you need to ensure bundle.js is loaded after the elements you need to reference:

<body>
<h2>React with ES5</h2>
 <div id="app"></div>
 <script src="dist/bundle.js"></script>
</body>