This article is part of Building Realtime Apps Tutorials series, updated on a regular basis.

ReactJS has been an awesome development in the way we think about data-driven user interfaces. By eschewing the n-way data-binding we see in many other JavaScript frameworks, it provides a simple, unidirectional flow for handling state in client-side code. Whenever the underlying data of your views change, React automatically re-renders your components. As a result, it makes building views with lots of moving parts a cinch.

Such a philosophy works very well with realtime applications, such as chat apps, dashboards, activity streams, where there is lots of incoming data, and therefore state being constantly modified. Pusher’s evented API makes this even more simple to handle. All you need to do is listen for any incoming data – whether on your server or other clients – and set the the component’s underlying state. React will efficiently re-render your component by calculating the diffs in the DOM and applying the changes. This makes it a great fit for realtime apps with high update rates!

This quick tutorial will lead you through building a basic, group chat app, similar to our demo here. The concepts demonstrated here will extend to anything realtime you wish to build: dashboards, activity streams, collaboration apps, and so on. I will demonstrate how easy it is to drop in Pusher to make any React app, new or existing, realtime.

Step 0: Setting Up

On our backend I’ll be using Flask – but there will only be two routes: one rendering an index.html file, and another accepting a JSON post. Everything here can be extended to any framework you wish to use, particularly as we have libraries in all popular languages and a consistent top-level API across those libraries. If you get stuck at any point, feel free to browse the source code.

All we want to do to get set up for now is set up Pusher and render our main file.

To set up Pusher we just install and import the pusher package and create an instance with our app credentials. You can get these by signing up to a free account.

from pusher import Pusher # get this package via `pip install pusher`

pusher = Pusher(
  app_id='your app id',
  key='your key',
  secret='your secret'
)

Let’s also render our main HTML file:

from flask import Flask, render_template, request

app = Flask(__name__,  static_url_path='/static')

@app.route("/")
def show_index():
    return render_template('index.html')

Within our HTML we’ll want to import React and Pusher:

<head>
  <title>Realtime Chat with Pusher + React</title>
  <script src="//fb.me/react-0.13.3.js"></script>
  <script src="//fb.me/JSXTransformer-0.13.3.js"></script>
  <script src="//js.pusher.com/3.0/pusher.min.js"></script>
</head>

Notice that for the purpose of this tutorial, we’ll be using React’s in-browser JSX transformer. You’ll receive a warning in the console, as for production environments it’s best to precompile your JSX beforehand.

Step 1: React in 2 Minutes

For our little chat app, the flow will be this: the user is asked to submit their Twitter username. Once they’ve done this, they are welcomed to the app, and will be allowed to create messages and see created messages.

So what, then, are our UI components? A fantastic thing about the philosophy of React is that it makes the developer reason through the views they will create and break things down. So far we have a Chat component, which represents our webpage, and will be the parent of all components. What else do we need?

  • A WelcomeView: this will allow the user to input their Twitter username. Once they have done so, it will simply welcome them to the app.
  • A MainView, which will be shown once the user is ‘logged in’. It will contain the MessageList and input as child components the user is now free to see and use.

Let’s first start with the WelcomeView, as it’s a very simple demonstration of how React works.

Now, the React philosophy is that your code should have as many stateless components as possible. Ideally, you should have any stateful components pass data to its subcomponents through props, which resemble HTML attributes. For example, our state here is the user’s username. Our Chat component will be in charge of it, and pass it down to subcomponents:

var Chat = React.createClass({

  getInitialState: function() {
    return {
      username: null
    };
  },

  render: function() {
    return (
      <div>
        <WelcomeView username={this.state.username} />
      </div>
    );
  }

});

We first initialize the Chat’s state, i.e. underlying data, with a null username. It will pass it down to the WelcomeView, and later our MainView.

First we must listen for a new username input to the WelcomeView. Let’s add an event handler called _onName to our WelcomeView tag:

<WelcomeView username={this.state.username} _onName={this._onName} />

Then let’s write our component:

var WelcomeView = React.createClass({

  render: function() {

    var view;
    var username = this.props.username;

    if (username) {
      view = <h1>Welcome {username}</h1>
    } else {
      view = <input onKeyPress={this.props._onName} placeholder="Please enter your Twitter username" />
    }

    return view;
  }

});

To break this down: we access the username prop handed down by the Chat super-component using this.props.username. If there is a username, we just want to render an h1 that welcomes the user. If not, we just want to render an input. Using React’s built in event handler, onKeyPress, we can register our _onName function to execute whenever a key is pressed.

Let’s go back to Chat.js and write this function, which we can pass down to the WelcomeView via a prop:

var Chat = React.createClass({

  ...

  _onName: function(e){
    if (e.nativeEvent.keyCode != 13) return;
    var username = e.target.value;
    this.setState({username: username});
  },

  ...

});

This should be straightforward: if the user doesn’t press the enter key, then return. If they do, get the username from the input element. After that, magic: we just call this.setState, passing in what property we wish to change and its value.

Open up your browser and head to your app. When you enter a username, the Chat component will have its username state to whatever you give it. Then React will re-render the affected component, the WelcomeView, which now has the username passed to it through props. Now it will show a welcome message instead of an input.

So hopefully by now you can see the awesome power of React in this mini-example. Just changing the state of the component will call its render method again, and the render methods of its affected subcomponents.

Now that’s done, we can start showing our MainView, and sending messages.

Step 2: Sending Messages

For the purpose of this tutorial, we’ll just be creating messages by getting an input value and sending an AJAX post to the server.

So let’s get writing our MainView and add it to our Chat parent component:

// Chat.js
  ...
  render: function() {
    return (
      <div>
        <WelcomeView username={this.state.username} _onName={this._onName} />
        <MainView username={this.state.username} />
      </div>
    );
  }
  ...
// MainView.js

var MainView = React.createClass({

  getInitialState: function() {
    return {
      messages: [] 
    };
  },

  render: function() {

    if (!this.props.username) var style = {display:'none'}

    return (
      <div style={style}>
        <input placeholder="Type your message" onKeyPress={this._onMessage} />
      </div>
    );
  }

});

The initial state of the MainView will an empty messages array. When we listen for new messages we’ll be modifying this later. The props handed to it by the Chat component will be the username. If there is no username, we set the style of MainView to {display: 'none'}, otherwise we show it.

For now, we will render an input, and – like before – listen for a keypress, passing in an _onMessage method. All this will do is create a message from the user’s username, the text they entered, and a timestamp:

_onMessage: function(e){
  if (e.nativeEvent.keyCode != 13) return;

  var input = e.target;
  var text = input.value;

  // if the text is blank, do nothing
  if (text === "") return;

  var message = {
    username: this.props.username,
    text: text,
    time: new Date()
  }

  $.post('/messages', message).success(function(){
    // reset the input
    input.value = ""
  });

},

On our server, let’s create a /messages endpoint:

@app.route('/messages', methods=['POST'])
def new_message():
  username = request.form['username']
  text = cgi.escape(request.form['text']) # let's escape it for security's sake
  time = request.form['time']

  # ENTER MAGIC HERE

  return "great success!"

Now comes the best bit: updating your UIs in realtime whenever the server gets the message.

Live Chat Messages

At our endpoint, once we have the username, text, and time variables, we can just send a Pusher event. You can also choose to persist your data here, but we won’t for the sake of the demo.

To test the integration, you can open up the Pusher Debug Console on your dashboard. Whenever a message comes in at your endpoint, just call trigger and pass in a channel_name, e.g. messages, an event_name, e.g. new_message, and your JSON payload.

@app.route('/messages', methods=['POST'])
def new_message():

  ...

  pusher.trigger('messages', 'new_message', {
    'text': text,
    'username': username,
    'time': time
  })  

On your app, once you enter a message, you should see them appear in realtime on your debug console. Pretty cool, huh? Not really – we don’t have a chat app yet. Let’s sort this out.

Within your MainView‘s render method, let’s add our MessageList component:

render: function() {

  if (!this.props.username) var style = {display:'none'}

  return (
    <div style={style}>

      <MessageList messages={this.state.messages}  />

      <input placeholder="Type your message" onKeyPress={this._onMessage} />
    </div>
  );
}

Create a file called MessageList.js and the React class within it:

var MessageList = React.createClass({

  render: function() {

    var list = this.props.messages.map(function(message){

      return  (
        <li>
          <img src={"https://twitter.com/"+message.username+"/profile_image?size=original"}/>
          <b>{message.username} - {message.time}</b>
          <p>{message.text}</p>
        </li>
      )

    });

    return (
      <ul>
        {list}
      </ul>
    );
  }

});

The list of messages will be handed down to the MessageList via props. It will take this list, map it and create lis out of each item, with its Twitter avatar, username, timestamp and text.

As I said before, our MainView component will own the messages array. We just need to append new messages to this array when they come in and the MessageList will re-render. Before we do so, we need to set up Pusher using React’s built-in life-cycle events. These events – such as componentWillMount, componentDidMount, componentWillUnmount – are called when a component will be created, has been created, or will be destroyed. React has a few others, which you can find documented here.

To initialize Pusher when a component is about to be mounted to the DOM:

// MainView.js

componentWillMount: function() {

  this.pusher = new Pusher('YOUR_APP_KEY');
  this.chatRoom = this.pusher.subscribe('messages');

},

Here we simply initialize our Pusher instance with our app key. Then we subscribe to our messages channel, and store this channel in chatRoom property. When the component does mount, let’s listen for events triggered, and pass a callback. We also need to pass this as a third argument, to set the context of the callback function as the React component:

// MainView.js

componentDidMount: function() {

  this.chatRoom.bind('new_message', function(message){
    this.setState({messages: this.state.messages.concat(message)})
  }, this);

},

Now whenever a message comes in, we add it to this.state.messages, and call setState, to give the MainView an updated array of messages. React will automatically call render and update the MessageList.

Now you have a nice, encapsulated realtime chat app, with an uncomplicated data flow!

Get Pushing!

Hopefully you found this a simple introduction in how to create realtime apps with React and Pusher. There are many ways you can extend this tutorial to make for an improved application:

  • Use React with Flux. For a larger application with more underlying data, Flux would make it easier to control the flow of state to your React components.
  • Use Pusher client events to send messages from one client to another. You could use our webhooks to notify your server when messages are sent, allowing you to persist them in your database.
  • Use Pusher presence channels to create live user lists and show who’s online in realtime.

Even at this stage, I hope I’ve demonstrated how Pusher and React work well together. The setup is quick and painless, while Pusher’s event-based system fits well into React’s declarative, unidirectional data flow. When applied to larger scale applications, the two would play even better together. Combining React’s performant DOM rendering, and Pusher’s capacity to automatically scale your messaging capacity to millions, applications with large numbers of live updates become easily manageable.

Further reading

About Jamie Patel

Jamie is one of Pusher's Growth Engineers, and loves playing with new technology and working some realtime magic on them. Originally a literature graduate and founder of two magazines, he enjoys exploring the creative side of coding and is continually looking to learn new things.