My biggest take away from React Europe 2016 arrived four days later

Sometimes I don’t see the wood for the trees. I was about ten meals in to the tasty recipes I found on www.deliciouslyella.com before I realised all the recipes were vegan. I was so entranced by the healthy, easy to cook recipes that I didn’t notice one of the most important features, even though I didn’t need to, in order to enjoy the good food I was making.

It’s been the same with React. I actually sat up in bed at 4am with the realisation of what was core to React, months after starting to use it!

I came to React after 10 years of programming in Ruby in the Rails framework, and a similar period of time programming in Objective C, mainly for iOS but a little for MacOS. I was drawn in by the promise of both “the new shiny thing” and also the promise of cross platform development for mobile. Whilst I had programmed in Java before, I really didn’t want to have to learn a whole new world SDKs to port my apps from iOS to Android. I wasn’t comfortable with programming in JavaScript (something I had written off as a toy language), but I seemed to be able to get by if I transpiled in my head what I was trying to write from Ruby to Javascript.

This was relatively easy in JavaScript as it was nine months ago, as long as I remembered to use the poorly understood magic of bind(this). Then ES6 and ES7 became all the rage. It seemed to offer language constructs I was more familiar with, like class declarations. But it also brought with it a whole new strange syntax of things like declaring functions with fat arrows. But the reason for this, and the power offered, passed me by.

Perhaps one of the strongest reasons I had for adopting React so quickly was Redux. When I read about how Redux worked, how it provided a single source of truth for an application, and for the first time how important immutability was, I felt the same rush of excitement as I did 10 years ago when I started programming Ruby for the first time. Redux made the pain of JavaScript worthwhile.

Fast-forward to last week, when I attended ReactEurope 2016. There were a number of excellent talks given on all levels of React and React Native. My favourite was the talk by Cheng Lou “On the Spectrum of Abstraction” (watch it on youtube here). It made me think about computer science concepts I learnt years ago but hadn’t used mindfully since. But more relevant to this post was the talk by Andrew Clark on “Recomposing your React application”, available online here. Here he talks about not using inheritance (the classic object oriented tool) but instead higher order components, components transformed by functions into new components with more features.

Dan Abramov spoke about “The Redux Journey” (online here). He mentioned two things I’d heard of before, the Om framework and the Elm language. I took a quick note whilst listening to the talk to investigate both further. So when I was scanning the Hacker News my attention was grabbed by the article Putting down Elm. I read that, fascinated by the things functional programming languages have to offer. Yesterday, my eye was caught by an another article about understanding the Elm type system. I scanned that, and at the end found a link to Professor Frisby’s Mostly Adequate Guide to Functional Programming.

And here it was, in the first two sentences: “This is a book on the functional paradigm in general. We’ll use the world’s most popular functional programming language: JavaScript”. I had a quick read of the book and loaded it onto my phone, ready to read on the journey to work in the morning. And with that I went to bed.

And so finally, at 4am, I wake up and see what has been staring me in the face for the last 6 months of learning React and React Native. JavaScript is a functional programming language. React is a functional programming framework. Look at how Redux works – actions are functions. Reducers are pure functions. Things that made no sense before such as React stateless components (see here for a good introduction) are functions. Andrew Clark’s talk of HOCs was really about functions. React’s basic architecture of components and unidirectional data flow is really all based around functional programming.

I returned from ReactConf determined to become a better JavaScript programmer and so a better React programmer, and to learn all ES6 and ES7. I think this single insight alone is a huge step forward, and I’m excited to find a way into functional programming again, all these years after programming in Lisp at university and thinking it was the best way to program, before switching back to imperative programming once the course was complete. For me, it shows React and React Native are more than just JavaScript framework, they are a whole new way of thinking and coding.

Digging into React and Redux with Rails 5’s ActionCable

One of the exiting new technologies in Rails 5 is ActionCable, essentially an implementation of web sockets that allows real time communication between client and server.

We’ve been re-implementing our helpdesk system by rebuilding the user interface as a React application.  A majority of the user interaction is viewing lists of tickets, which are being constantly updated by the helpdesk staff.  This seemed a perfect use of ActionCable to allow for live updating of people’s ticket lists.

The majority of tutorials embed the React app into the Rails app using gems such as react-rails.  This gives you access to the Rails generated Javascript App object for making ActionCable calls, and defining what happens when ActionCable messages are sent back inside of the Rails app using Coffeescript, but I wanted to build a more pure ReactJS app separate from the Rails application.

Our app is based on Redux, so the concept we wanted to investigate was sending updates to the server as an ActionCable message, and receive updated tickets back over the ActionCable channel, and have those feed back into the Redux store.

Rails and ActionCable

To start on the server side, we created a very simple ActionCable channel.  We skip the user authentication and separation of streams by user and simply broadcast all ticket changes to all subscribers.  We define two methods, send_all_tickets which can be used so set the initial store state (and for forcing refreshes) and new_ticket which is called when a ticket is added to the system.  In our full system we would add this ticket into the database, but for this proof of concept we just broadcast the new ticket out to all subscribers.

require 'securerandom'

class TicketsChannel < ApplicationCable::Channel
  def subscribed
    stop_all_streams
    stream_from "tickets"
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end

  def send_all_tickets
    Ticket.all.each do |ticket|
      message_data = {
        action: 'new_ticket',
        ticket: ticket
      }
      ActionCable.server.broadcast('tickets',message_data)
    end
  end


  def new_ticket(ticket)
    # normally would create a ticket in the database here
    
    ticket = {
      subject: ticket["ticket"],
      id: SecureRandom.uuid
    }
    message_data = {
      action: 'new_ticket',
      ticket: ticket,
    }
    ActionCable.server.broadcast('tickets',message_data)
  end

  private


end

On the React side, we assume we are working with a browser that supports WebSockets natively.

We start by setting up React and importing our Redux action for adding tickets to the store.

import { addTicketToStore } from '../actions'

We then implemented a simple WebSocket interface for receiving messages from ActionCable and for sending messages to the server and store it in the component state.


  componentDidMount() {
 
    let ws= new WebSocket("ws:localhost:3000/cable" )
    ws.onopen = function() {
        let identifier = JSON.stringify({channel:'TicketsChannel'})
        let msg = JSON.stringify({command:'subscribe', identifier:identifier})
        ws.send(msg);
     };

     ws.onmessage = (evt) => {
        var received_msg = evt.data;
        this.process_message(received_msg)
     }

     ws.onclose = function()
     {
        // websocket is closed.
        console.log("Connection is closed...");
     };

     this.setState({ws: ws})
  }

Any messages we receive from the Rails server are processed and the message information extracted out, and if the message is a new ticket, we add the ticket into the Redux store:

  process_message(received_msg) {

    let parsedMessage = JSON.parse(received_msg)
    if (parsedMessage["identifier"]!="_ping") {
      console.log("Message is received..." +  received_msg);
      if (parsedMessage["message"]) {
        let message=parsedMessage["message"]
        if (message['action']=='new_ticket') {
          this.props.dispatch(addTicketToStore(message["ticket"]))
        }
      }
    }

  }

and here we send a message to the server to retrieve all tickets

  get_all_tickets() {
    console.log('send request for all tickets')
    let identifier = JSON.stringify({channel:"TicketsChannel"})
    let data = JSON.stringify({action:'send_all_tickets'})
    let msg = JSON.stringify({command:'message', identifier:identifier,data:data})
    this.state.ws.send(msg);
  }

 

We render a simple interface for listing our tickets from the store :

 



      <div className="main-container">

        <div className="container">
          <a href='#' onClick={e => {
              e.preventDefault()
              console.log("refresh")
              this.get_all_tickets()
            }}>Refresh All tickets</a>
          <h3>Tickets:</h3>
          <ul>
          {this.props.tickets.map(function(ticket){
            return <li key={ticket.id}>{ticket.subject}</li>;
          })}
          </ul>
        </div>
        <div>

 

and finally render a simple interface to submit new tickets by sending a message to the server:

 


      <form onSubmit={e => {
        e.preventDefault()
        if (!input.value.trim()) {
          return
        }
        let identifier = JSON.stringify({channel:"TicketsChannel"})
        let data = JSON.stringify({action:'new_ticket', ticket:input.value})
        let msg = JSON.stringify({command:'message', identifier:identifier,data:data})

        this.state.ws.send(msg);
        input.value = ''
        }}>
        <input ref={node => {
          input = node
        }} />
        <button type="submit">
          Add Ticket
        </button>
      </form>

We end up with an interface like this:

Tickets List

As a new ticket subject is typed and “Add Ticket” is clicked, every browser open to this page updates with the new ticket added to the list.

This is just the beginning of how we see our Rails app and our ReactJS Redux app interacting, but we’re very excited but what’s possible. Our next steps are to make a generalised ActionCable component to feed actions to the store.

You can download the whole project from github here