React JS Web Site Example (Almost like real life).
Tags: react, redux, javascript, node
Published: 2017-04-16 04:44:58

---
title: React JS Web Site Example (Almost like real life).
published: true
description: A React JS example that resembles a real life scenario.
tags: React, Redux, JavaScript, Node
---

I've been trying to use react on my personal projects for a couple weeks now, but I found out that there isn't one example on the internet (that I could find) that ressembles what I want in a real life scenario.

Asynchronous HTTP requests, loading animations, error pages, etc. None of those things are covered by one concise example that can be found on the first two pages of google.

Having said that, I took one [example](https://www.sitepoint.com/how-to-build-a-todo-app-using-react-redux-and-immutable-js/) that took me far enough, and started researching and building on top of it.

## What are we going to do?

We are going to build a simple To Do List web application.

To do this, we are going to build a very simple REST API in Node.js using [rest-api-starter](https://www.npmjs.com/package/rest-api-starter), and a web site based on React.JS, Redux and Bootstrap.

## What am I going to need to follow this tutorial?

First, a Node.js 6 installation, an IDE and a browser (which you probably have already, as you are reading this). Instructions on how to install Node.js can be found [here](https://nodejs.org/en/).

Second, a Python 2.7 installation. If you are on a Mac OS or an Ubuntu based system, you already have it. Instructions on how to install Python can be found [here](https://www.python.org/downloads/).

All the commands I'll provide to install, run and do stuff were tested on Linux Mint 18. They'll probably work on Mac OS without any issue. If you're working on windows I'm really sorry.

## Can we start coding already?

Allright, first of all, let's make our directories.

```
$ mkdir todo-api
$ mkdir todo-site
```

### API project

Now, let's start with the API. We are going to `cd` to the API directory, and run `npm init`.

```
$ cd todo-api
$ npm init
```

You can leave all the defaults.

Now we have a node project there, we are going to install `rest-api-starter` and `uuid` (for id generation and stuff).

```
$ npm install --save rest-api-starter uuid
```

Now, `rest-api-starter` requires a tiny configuration file on a subdirectory called `config`.

```
$ mkdir config
$ cd config && touch default.json
```

The `config/default.json` file should look exactly like the one below:

```
{
  "app": {
    "http": {
      "port": 8100,
      "host": "0.0.0.0",
      "queue": 10,
      "secret": "",
      "transactionHeader": "X-REST-TRANSACTION"
    },
    "log": {
      "level": "info",
      "transports": [
        {
          "type": "console"
        }
      ]
    }
  }
}
```

Now, let's code our rest API. We need CORS support to be able to easily develop on our local environment and three handlers:

* POST `/todos`: Create an item.
* GET `/todos`: Retrieve all items.
* PATCH `/todos/:id`: Mark an item as done or undone.

Also, an OPTIONS handler for each path should be implemented for CORS support. So, our `index.js` file will look like this:

```
const uuid = require('uuid');
const serveBuilder = require('rest-api-starter').server;
const todos = [];

const router = (app) => {

    app.use(function(req, res, next) {
        res.header("Access-Control-Allow-Origin", "*");
        res.header("Access-Control-Allow-Methods", "GET, POST, PATCH, OPTIONS");
        res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        next();
    });

    app.options('/todos', (request, response) => response.status(200).send());

    app.post('/todos', (request, response) => {
        const todo = {
            'id': uuid.v4(),
            'isDone': false,
            'text': request.body.text
        };
        todos.push(todo);
        response.send(todo);
    });

    app.get('/todos', (request, response) => {
        response.send(todos);
    });

    app.options('/todos/:id', (request, response) => response.status(200).send());

    app.patch('/todos/:id', (request, response) => {
        let result = null;
        todos.forEach((todo) => {
            if (todo.id === request.params.id) {
                todo.isDone = !todo.isDone;
                result = todo;
            }
        });

        if (!result) {
            response.status(404).send({'msg': 'todo not found'});
        } else {
            response.send(result);
        }
    });

};

serveBuilder(router);
```

Now, add `"start": "node index.js"` to the `scripts` section of your package.json file to start the server. By running `npm run start` on the root of the API project, you'll have your server listening on `http://localhost:8100`.

### Site project

Now we're going to cd to the site project and run an `npm init` there. Defaults are fine here too.

```
$ cd todo-site
$ npm init
```

And now, we install the dependencies we need:

```
$ npm install --save babel-core babel-loader babel-preset-es2015 babel-preset-react bootstrap jquery superagent webpack react react-dom react-redux redux redux-thunk style-loader css-loader
```

#### Webpack

We'll be using webpack to transpile and unify all the code into una file called `bundle.js`, so it will be convenient to add `"build": "webpack --debug"` and `"serve": "npm run build && python -m SimpleHTTPServer 8080"` to the scripts section in our package.json.

Now we'll need a `webpack.config.js`.

```
const webpack = require('webpack');

module.exports = {
    entry: {
        main: './src/app.js'
    },
    output: {
        path: __dirname,
        filename: 'bundle.js'
    },
    module: {
        loaders: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
                query: { presets: [ 'es2015', 'react' ] }
            },
            {
                test: /\.css$/,
                loader: "style-loader!css-loader"
            },
            {
                test: /\.(png|jpg|gif|ttf|svg|woff|woff2|eot)$/,
                loader: "url-loader"
            }
        ]
    },
    plugins: [
        new webpack.ProvidePlugin({
            $: "jquery",
            jQuery: "jquery",
            bootstrap: "bootstrap"
        })
    ]
};
```

This webpack configuration transpiles all the javascript files that are using ES6 and JSX, and then puts them together, with all their dependencies, in one big file called `bundle.js`. 

If any stylesheet is required from `src/app.js`, it will import it and add it to the bundle (following any imports made from the stylesheets) and the generated bundle script will add a `<style>` tag to the HTML.

It also uses the `ProvidePlugin` to expose JQuery and bootstrap, so we can forget about importing them.

#### Stylesheets

Now, let's start with some structure. Let's create a directory called `css` in the root of the project and add the following `app.css`.

```
@import "../node_modules/bootstrap/dist/css/bootstrap.min.css";
```

That stylesheet just imports bootstrap, but you can add custom style and import any stylesheet you want there. That should be the entrypoint for all the stylesheets in the project.

#### HTML. Site entrypoint.

Then, we create our `index.html` in the project.

```
<!DOCTYPE html>
<html>
    <head>
        <title>Todo List</title>

        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    </head>
    <body>
        <div id="app"></div>

        <script src="bundle.js"></script>
    </body>
</html>
```

This is a pretty simple HTML file. It has a title, the viewport recommended by bootstrap, a `div` with the id `app` and the import of our bundle.

That div called `app` will be our application container. We'll tell react to render its components there.

#### React Components

Let's write our React.js components. A React component is an independent piece of code that receives some props and renders HTML from that props. It should JUST be React, a component's code should know nothing about Redux. Just presentation. (I can't stress this enough).

Create a directory called `src` on the root of the project, and write the code below to a file named `components.js`.

```
import React from 'react';

function Todo(props) {
    const { todo } = props;
    if (todo.isDone) {
        return <del>{todo.text}</del>
    } else {
        return <span>{todo.text}</span>
    }
}

function TodoList(props) {

    const { todos, toggleTodo, addTodo } = props;

    const onSubmit = (event) => {
        event.preventDefault();

        const textInput = document.getElementById('todo-input');

        const text = textInput.value;

        if (text && text.length > 0) {
            addTodo(text);
        }

        textInput.value = '';
    };

    const toggleClick = id => event => toggleTodo(id);

    return (
        <div className='todo-list-container'>
            <div className="panel panel-default">
                <div className="panel-body">
                    <form onSubmit={onSubmit}>
                        <div className="form-group">
                            <label>To Do Text: </label>
                            <input id="todo-input" type='text'
                                   className='todo-input form-control'
                                   placeholder='Add todo' />
                        </div>
                        <button type="submit" className="btn btn-default">Submit</button>
                    </form>
                </div>
            </div>
            {
                todos.length > 0 ?
                    <div className='todo-list list-group'>
                        {todos.map(t => (
                            <a key={t.id}
                                className='todo-list-item list-group-item'
                                onClick={toggleClick(t.id)}>
                                <Todo todo={t} />
                            </a>
                        ))}
                    </div> :
                    <div className="alert alert-info" role="alert">ToDo list is empty.</div>
            }
        </div>
    );
}

function Layout(props) {
    return (
        <div className='container'>
            <div className='row'>
                <div className='col-lg-6 col-lg-offset-3'>
                    <div className='page-header'>
                        <h1>To Do List <small>Keep it organized.</small></h1>
                    </div>
                    {props.children}
                </div>
            </div>
        </div>
    )
}

function ProgressBar(props) {
    const { completed } = props;

    const style = { 'width': completed + '%'};

    return (
        <div className="progress">
            <div className="progress-bar progress-bar-striped active" role="progressbar" aria-valuenow={completed} aria-valuemin='0' aria-valuemax='100' style={style}>
                <span className="sr-only">{completed}% Complete</span>
            </div>
        </div>
    )
}

export function TodoPage(props) {

    const {state, toggleTodo, addTodo, retrieveTodos } = props;

    if (state.error) {
        return (
            <Layout>
                <div className="alert alert-danger" role="alert">{state.error.toString()}</div>
                <input className='retry-button btn btn-default' type='button' value='Retry' onClick={retrieveTodos}/>
            </Layout>
        );
    } else if (state.initialized) {
        return (
            <Layout>
                <TodoList todos={state.todos} toggleTodo={toggleTodo} addTodo={addTodo} />
            </Layout>
        )
    } else {
        retrieveTodos();
        return (
            <Layout>
                <ProgressBar completed="45"/>
            </Layout>
        );
    }

}

```

That's our presentation layer. We export one function, called `TodoPage`, which uses some components only available inside the module.

These components receive the application's state, and three actions: toggleTodo, addTodo, retrieveTodos. The components don't know what they do, they just know how to invoke them, and they don't even care about a return value.

Notice that the components receive the state and the actions, and just cares about how the state is displayed, and how are those actions mapped to HTML events.

#### API Client

Now, let's write our API client using `superagent` and ES6 promises. under a directory called `src` created on the root of our project write the following code on a file called `client.js`.

```
import * as superagent from "superagent";

export function get() {

    return new Promise((resolve, reject) => {
        superagent.get("http://localhost:8100/todos")
            .end((error, result) => {
                error ? reject(error) : resolve(result.body);
            });
    });

}

export function add(text) {

    return new Promise((resolve, reject) => {
        superagent.post("http://localhost:8100/todos")
            .send({'text': text})
            .end((error, result) => {
                error ? reject(error) : resolve(result.body);
            });
    });

}

export function toggle(id) {

    return new Promise((resolve, reject) => {
        superagent.patch("http://localhost:8100/todos/" + id)
            .end((error, result) => {
                error ? reject(error) : resolve(result.body);
            });
    });

}
```

That module exports three functions:

* get: Executes a GET request to `/todos` in our API to retrieve all To Do items.
* add: Executes a POST request to `/todos` in our API to add a To Do item.
* toggle: Executes a PATCH request to `/todos/:id` to change the `isDone` flag of that item.

#### Redux Actions

Let's talk about actions...

Actions, in Redux, are pieces of information that get sent to the store. These payloads trigger modifications on the state of the application. 

Actions are basically Redux's way of saying "Hey! This happened!".

*WARNING*: Not actual modifications, the state of the application shoud be treated as an immutable object. You should never modify the state, but copy it, change the copy and keep going. More on it further down.

Actions are generated via action builders. These builders are functions that get invoked with some information and return the action, which is sent to the store via a `dispatch` function provided by Redux.

An interesting concept, necessary for real world applications, are asynchronous actions. These aren't actually just a piece of information, but another function that receives the `dispatch` function as parameters and, after some asynchronous operations, dispatches another action. Let's explain it with some code.

Write the following code on a file called `actions.js` under the `src` directory.

```
import { get, add, toggle } from './client';

export function addTodo(text) {
    return (dispatch) => {
        add(text)
            .then(get)
            .then((todos) => dispatch(receiveTodos(todos)))
            .catch((err) => dispatch(error(err)));
    };
}

export function toggleTodo(id) {
    return (dispatch) => {
        toggle(id)
            .then(get)
            .then((todos) => dispatch(receiveTodos(todos)))
            .catch((err) => dispatch(error(err)));
    };
}

export function retrieveTodos() {
    return (dispatch) => get()
        .then((todos) => dispatch(receiveTodos(todos)))
        .catch((err) => dispatch(error(err)))
}

function receiveTodos(todos) {
    return {
        type: 'RECEIVE_TODOS',
        payload: todos
    }
}

function error(err) {
    return {
        type: 'ERROR',
        payload: err
    };
}
```

We here are defining all the behavior of our application. 

Our application has to retrieve To Do items from the API, toggle them and create them. These actions are asynchronows. 

* The addTodo action builder returns an asynchronous action that, after posting a new To Do item to the API, and retrieving all the To Do items again, dispatches the `receiveTodos` action. On error, it dispatches the `error` action.

* The toggleTodo action builder returns an asynchronous action that, after toggling the To Do item on the API, and retrieving all the items again, dispatches the `receiveTodos` action. On error, it dispatches the `error` action.

* The retrieveTodos action builder returns an asynchronous action that, after retrieving all the To Do items from the API, dispatches the `receiveTodos` action. On error, it dispatches the `error` action.

Notice that these (not as they are defined here, we'll see how) are the actions that are used by our components to handle HTML events.

The other two actions are ordinary actions, that receive some data and returns a payload.

* The receiveTodos action builder returns an action of type `RECEIVE_TODOS` with the retrieved todos as payload.

* The error action builder returns an action of type `ERROR` with the received error as payload.

This might sound confusing. I think Redux is not an easy to understand state manager, its concepts are pretty hard to understand, but if you put this in practice and read the code you'll end up liking it a lot.

#### Redux Reducer

This takes us to the reducers. A reducer is a function that receives the current state of the application and an action. As stated before, an action is a way of saying that something happened, and a reducer grabs that event/information and does what it need to do to the state to impact that event on it.

Basically, they receive the current state of the application and an action that was performed (an event or something, like a user click for example) and return the new state of the application.

Let's see more code. Write the following code on a file called `reducer.js` under the `src` directory.

```

const init = {'todos': [], 'error': false};

export default function(state=init, action) {
    switch(action.type) {
        case 'RECEIVE_TODOS':
            return {'todos': action.payload, 'error': false, 'initialized': true};
        case 'ERROR':
            return {'todos': [], 'error': action.payload, 'initialized': true};
        default:
            return state;
    }
}
```

This reducer is defining the initial state of the application and taking care of handling the actions it receives.

If the action it received is of type `RECEIVE_TODOS`, it returns the new state, ensuring that `error` is false, `initialized` is true and `todos` contains the received todos.

If the action it received is of type `ERROR`, it returns the new state, ensuring that `error` contains the ocurred error, `initialized` is true and `todos` is an empty array.

If the action it received has no handler, it just passes through the current state of the application as no changes are to be applied.

Sorry I repeat myself so much, but this concept took me a while: React components receive Redux's action builders, and ivoke them on HTML events. These events get dispatched to Redux's reducers to do what they have to do to the state based on the information provided by the action.

#### Container Components

Another new concept: containers. Containers are a type of component, they are called `Container Components`. They do the connection between React components (which are just presentational components and know nothing about redux), and redux's actions and state.

They basically wrap the react component, and grabs the state and the actions and maps them to props. 

Let's see the code. Write the following code in a file called `containers.js` under the `src` directory.

```
import { connect } from 'react-redux';
import * as components from './components';
import { addTodo, toggleTodo, retrieveTodos } from './actions';

export const TodoPage = connect(
    function mapStateToProps(state) {
        return { state: state };
    },
    function mapDispatchToProps(dispatch) {
        return {
            addTodo: text => dispatch(addTodo(text)),
            toggleTodo: id => dispatch(toggleTodo(id)),
            retrieveTodos: () => dispatch(retrieveTodos())
        };
    }
)(components.TodoPage);
```

It grabs our `TodoPage`, our actions and the state, and puts them into props, for our component to see. This is where everything is glued together.

#### Web Application Start Up

Let's go to our application entry point now. Write the following code in a file called `app.js` under `src`.

```
import '../css/app.css';

import React from 'react';
import { render } from 'react-dom';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import reducer from './reducer';
import { TodoPage } from './containers';

const store = createStore(reducer, applyMiddleware(thunk));

document.addEventListener("DOMContentLoaded", function() {

    render(
        <Provider store={store}>
            <TodoPage />
        </Provider>,
        document.getElementById('app')
    );

});
```

This file is importing our css entry point file, our reducer and the TodoPage container (not the component, the container).

Then, it creates the Redux store (basically, where te state lives). You might have noticed that our reducer is not handling any of our asynchronous actions, thats why we are passing that `applyMiddleware(thunk)` to `createStore`. `redux-thunk` takes care of handling asynchronous actions just like that.

We now wait for the DOM to be loaded, and then calling React's `render` function. This function receives a component and the container HTML element (that's our div#app from index.html).

The component we are passing to the `render` function is a `Provider` tag, with *only one child* (this is important, it can not have more than one child), which is our `TodoPage` container component. We are passing our store to the `Provider` tag by the way.

#### You're ready to go

We now can run `npm run serve` in the root of the site project, and `npm run start` in the root of the API project. Now we can visit `http://localhost:8080/` and use our To Do list.

## Conclusion

I find this pair (React, Redux) to have a pretty complex ramp up, but once you get the hang of it, applications are written quickly and the code looks great too. Yeah, it's a lot of boiler plate sometimes, but it looks nice and it actually performs pretty well too.

I come from the JQuery world, then moved on to Angular.JS, and now I moved to React.JS and Redux and I actually like it.

You can find the code to this example [here](https://github.com/svinci/react-example).

See you in the comments!