Adding react-bootstrap to a React app

Adding Bootstrap to an existing or new React app is not as obvious or easy as you would think, because of Bootstrap’s dependencies on other libraries, like jQuery (and see answers to Quora question here).

The react-bootstrap module is a React specific implementation of Bootstrap that provides JSX components for a number of the Bootstrap provided styles and components, and even layout CSS encapsulated as JSX components like: <Grid>, <Row> and <Col>

Installing it via npm is as simple as:

npm intall --save react-boostrap

You then import what you need from the module like:

import {Bootstrap, Grid, Row, Col} from 'react-bootstrap';

and then you quickly discover that the CSS based layout is not working like you’d expect. If you check the Getting Started section it mentions:

Because React-Bootstrap doesn’t depend on a very precise version of Bootstrap, we don’t ship with any included css. However, some stylesheet is required to use these components. How and which bootstrap styles you include is up to you, but the simplest way is to include the latest styles from the CDN.

Ok. So you can follow their example and load from the Bootstrap (or other) CDN, but what if you want to manage Bootstrap as an npm module too? This question is answered in this post here. What you need is to install bootstrap:

npm install --save bootstrap

and then include it into your main App.jsx with:

import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap/dist/css/bootstrap-theme.css';

and you’re up and running. Not that obvious but once you’ve setup this once, probably makes more sense the next time.

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

 

 

Manually adding create-react-app scripts to an existing React app

create-react-app saves you a ton of time to get a new React app set up with all the dependencies you need for an ES6 based React app using Babel and webpack. Adding the scripts and config to an existing app though doesn’t seem to be documented in the user guide. This post here though walks through the basics.

All you need is to:

npm install react-scripts --save-dev

Then and the default scripts to your package.json:

"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
}

Then assuming you have structured your project folders the same as an app created with create-react-app, you’ll be able to ‘npm run start’ and off you go.