# Reactify

Published: 2015-11-06  
Canonical HTML: https://richorama.github.io/2015/11/06/reactify/

In this post we'll look at using react to render the data on the screen

---

In this series of blog posts, we're looking at how to set up a simple web app in node.

In the [previous installment](http://richorama.github.io/2015/10/02/enter-the-browser/) we looked at building an API in node, and then consuming it from a web app using browserify to build node modules into a JavaScript file for the browser.

In this post we'll look at using react to render the data on the screen.

## Installing dependencies

We'll need a couple more modules, lets install [react](https://www.npmjs.com/package/react), and [reactify](https://www.npmjs.com/package/reactify) (which allows browserify to build react components).

{% highlight text %}
> npm install react reactify --save
{% endhighlight %}

## Creating a react component

[React](https://facebook.github.io/react/) is a JavaScript library from Facebook for rendering user interfaces in the browser. It's not a full feature framework (like Angular), instead it's designed to handle the redrawing of UI components in response to changes in a data model. It takes the controversial decision to combine together logic and markup into reusable components. React also allows you to use JSX, which is a JavaScript where HTML is treated as a first-class concept. This can take a bit of getting used to. I like React. It's a pleasure to work with, and I've found the re-usability of components very useful.

Now lets create a new JavaScript file in our `client` directory, to hold the react component to render our todos. Let's call the file `todo-list.js`. 

The file will return a react component, using the node style `module.exports` variable, like this:

{% highlight javascript %}
var React = require('react');

module.exports = React.createClass({
  getInitialState:function(){
    return {text:''};
  },
  handleSubmit:function(e){
    e.preventDefault();
    this.props.onNewTodo(this.state.text);
    this.setState({text:''});
  },
  update:function(e){
    this.setState({text:e.target.value});
  },
  renderTodo : function(todo){
    return <li key={todo.key}>
      <strong>{todo.value}</strong> <a onClick={this.props.onDelete.bind(null, todo.key)} href="javascript:void(0);">delete</a>
    </li>
  },
  render:function(){
    return <div className="container">
      <h1>Todo List</h1>
      <ul>{this.props.todos.map(this.renderTodo)}</ul>      
      <form className="form-inline" onSubmit={this.handleSubmit}>
        <div className="form-group">
          <label>New todo</label>
          <input type="text" value={this.state.text} onChange={this.update} className="form-control" />
        </div>
        <button type="submit" className="btn btn-default">Add</button>
      </form>
    </div>
  }
});
{% endhighlight %}

There is a lot going on there, lets break it down.

1. On the first list we `require` react. This allows us to create react components.
1. We then call `React.createClass` to create the react component, and export it on the `module.exports` variable. This allows other files to `require` this one, and use the component.
1. The component has a `getInitialState` function, which returns an initial state for our component. We're using state to track the current value for the new todo that a user is entering. We'll return a state where the text is an empty string.
1. The `handleSubmit` function handles the form post when a new todo is created. It calls a `onNewTodo` function that must be set on the component when it's used. It also resets the text to empty.
1. The `update` function is called when the user types into the text box, we'll update the state accordingly.
1. The `renderTodo` function is called to render each todo. It returns the angle brackets to show the todo. Note that the `onClick` event for the delete button is bound to an `onDelete` function which must also be passed to the component.
1. Finally we render the main page, calling the `renderTodo` function for each of the todos. We also bind the `update` function to the `onChange` event for the text box, so it can update the state as we type.

> Ideally this component should be broken down into separate components: one for the todo list, and another with form for adding a new one. In the interests of simplicity I've kept them together.

## Connecting the API

I have made the intentional decision not to call the API directly from the react component. Instead, I pass in functions which are called by the component when data needs to be saved/deleted. This separates out the concern of the data loading from the rendering, allowing us to re-use the component, or test it in isolation.

We therefore need to connect the API up with the component, to do this we'll rewrite the `index.js` file:

{% highlight javascript %}
var React = require('react');
var http = require('./http-request');
var Todos = require('./todo-list');

var content = document.getElementById('content');

function newTodo(text){
  http.post('/api', {todo:text}, render);
}

function deleteTodo(key){
  http.del('/api/' + key, render);
}

function render() {
  http.get('/api', function(err, data){
    React.render(<Todos todos={data} onNewTodo={newTodo} onDelete={deleteTodo} />, content);
  });
}

render();
{% endhighlight %}

The index file now has functions to call the API for adding and deleting todos. The `render` function gets all the todos from the API, and renders our react components, passing in the data from the API, as well as the functions which call the API. The `render` function gets called immediately, to show the component on application startup. The render function is also used as the the callback when todos are created/deleted on the API.

That's all we need to do for now. We can build the react components by changing our command slightly to this (remember the `reactify` module we installed?):

{% highlight javascript %}
> browserify client/index.js -t reactify | uglifyjs > public/index.min.js
{% endhighlight %}

You can start the application as before with:

{% highlight javascript %}
> node server.js
{% endhighlight %}

The application should appear the same, only this time it's a SPA!
