« Back to home

Introduction to ReactJS + Flux with Ruby On Rails (Part II)

In this part of the ReactJS + Rails tutorial we're going to setup our simple chat project and discuss the concepts covered on the first part of this tutorial. If you missed the first part of this tutorial, feel free to go back to http://drnluz.com/introduction-to-reactjs-flux-with-ruby-on-rails-part-i/ and learn the basic concepts of ReactJS and Flux.

All the code presented on this tutorial is available on github: https://github.com/drnluz/react_chat

Project Setup

First of all, create a new rails project with the command rails new react_chat. Next, add some gems necessary for this project:

gem 'sprockets-es6'
gem 'react-rails'
gem 'flux-rails-assets'

And finally, run bundle install on the project root directory.

The gem sprockets-es6 is a gem that uses Babel JS to compile ES6 to ES5 specification of javascript. This is necessary since ES6 is not supported yet by the browsers. If you're not familiar with ES6 I recommend you to read the es6 features documented on github. ES6 has lots of improvements over "conventional" javascript and is really great to work with. Since I'm learning this new language myself, I intend to write about it in the future.

The gem react-rails is self descriptive. It adds the React library to the project.

The gem flux-rails-assets adds two important libs to our project. It adds the Flux library and the EventEmitter module (extracted from Node.js) to the project.

Some basic configuration is needed to make the gems work. According to the gem react-rails readme the following code addition is needed on app/assets/javascripts/application.js:

//= require react
//= require react_ujs

The gem's readme recommends adding a //= require components to application.js. That is not needed for now because the project structure for the javascript files won't use this directory.

The gem flux-rails-assets also need some requires on application.js:

//= require flux
//= require eventemitter

I recommend you to always read the README of the gems before using them, that's why I referenced the links for the github projects in this post.

The application barebones

Let's create a very basic layout for the sample application. First, add to the gem twitter-bootstrap-rails to the Gemfile, run bundle install and finally run rails g bootstrap:install static.

Next, create a controller named ChatsController with just an index action, then add a route on config/routes.rb and finally create a view on app/views/chats/index.html.erb with the following code in it:

<div class="container">
  <div class="row">
    <div class="col-md-4">
      <div class="panel panel-default">
        <div class="panel-heading">
          Friends list
        </div>
        <div class="panel-body">
          <div><a href="#">Friend 1</a></div>
          <div><a href="#">Friend 2</a></div>
          <div><a href="#">Friend 3</a></div>
        </div>
      </div>
    </div>
    <div class="col-md-8">
      <div class="panel panel-default">
        <div class="panel-heading">
          Messages
        </div>
        <div class="panel-body">
          <div class="clearfix bg-info">Message 1</div>
          <div class="clearfix bg-success">Message 2</div>
          <div class="clearfix bg-info">Message 3</div>
        </div>
        <div class="panel-footer">
          <input type="text" />
          <button>Send</button>
        </div>
      </div>
    </div>
  </div>
</div>

It is a very simple layout with the friends list on one side and the message list on the other.

Now we can start to write some react code!

The first react component

The first part of this tutorial presented the concept of a component. Now it is time to build the first React component for the chat application.

To create the first component, let's create a directory inside app/assets/javascripts called chat_application and inside that another directory called components. Inside that directory, create a file called message.es6.

class Message extends React.Component {
  render () {
    return (
      <div>Message from react component</div>
    )
  }
}

This code, written in es6 creates a component called Message. Every React component must extend from React.Component and have a render() method. This render method returns a JSX (if you are not sure what JSX is, refer to the first part of this tutorial) that will be rendered on the browser. Behind the scenes, the React library will add the result of the render method to the virtual DOM and compare it with the real DOM to update only the necessary parts of the page.

This new created react component can be used on our application using a handy helper provided by react-rails called react_component:

<%= react_component('Message') %>

Adding the react_component helper on the messages panel of the chat application should result in the following:

Cascading Components

React components can also be used inside the JSX render block like a HTML tag. React will automatically instantiate a new component and call it's render method to compose the final HTML. The following snippet shows an example of that behaviour.

return (
  <div>Something</div>
  <Message />
)

Using this React's feature we can proceed and build the rest of the components needed by our chat page. Looking at the layout of our application we can use the following slices to create the components:

After constructing the components the MessagesPanel component will look like:

class MessagesPanel extends React.Component {
  render () {
    return (
      <div className="panel panel-default">
        <div className="panel-heading">
          Messages
        </div>
        <div className="panel-body">
          <Message />
        </div>
        <div className="panel-footer">
          <input type="text" />
          <button>Send</button>
        </div>
      </div>
    )
  }
}

There are two important things to notice on this component. The first is that when using JSX the class for the HTML elements will be called className. This is a way to avoid conflict with the reserved work class from es6. The second thing to notice here is the usage of another component (<Message />) inside the JSX code as explained before.

The rest of the components won't be shown here. You can check the code for them on the github repository.

State

The React library has two main ways to handle data on it's components. They are states and props. The state, as the name suggests, stores all the data that describe the state of the component. When a state of a component changes, the react library re-renders the component and updates the DOM (if the element has any changes).

For example, the state of the Message component can be defined using this.state on the component's constructor.

class Message extends React.Component {
  constructor() {
    super();
    this.state = { message: "Message from react component" };
  }

  render () {
    return (
      <div>{this.state.message}</div>
    )
  }
}

To change the state of a component the function this.setState() must be used. For testing purpose, a setTimeout was added to the render() method of the Message component. After two seconds the message will be updated.

class Message extends React.Component {
  constructor() {
    super();
    this.state = { message: "Message from react component" };
  }

  render () {
    setTimeout(() => {
      this.setState({message: "New Message"})
    }, 2000);
    return (
      <div>{this.state.message}</div>
    )
  }
}

Props

Props is another way that React provides to handle data. Props are used to pass data between components. For example, if the MessagesPanel component holds the text for all the messages, this text can be passed to the Message component through props. In this case, the <Message /> element rendered on MessagesPanel receives an attribute called message. This attribute will be accessed by Message through this.props.message.

class MessagesPanel extends React.Component {
  render () {
    const text = "Text passed through props";
    return (
      <div className="panel panel-default">
        <div className="panel-heading">
          Messages
        </div>
        <div className="panel-body">
          <Message message={text} />
        </div>
        <div className="panel-footer">
          <ChatInput />
        </div>
      </div>
    )
  }
}

class Message extends React.Component {
  render () {
    return (
      <div>{this.props.message}</div>
    )
  }
}

Outro

This part of the ReactJS + Flux with Rails tutorial the ReactJS we discussed how to get started with React and Rails and learned how ReactJS components work. This is the most basic concept of React that every programmer who want to use this library should know.

On the next part of this tutorial the we're going to discuss the Flux architecture and apply it to this simple chat application.