Weekend Code Warrior: React.js

On February 5th 2015, Facebook announced that they intend to bring native React javascript development to both Android and iOS platforms. Their rationale for this decision stems from their opinion (long held by this author and probably most of humanity) that write once, use anywhere (in a mobile world) just doesn't work. When given the decision between experiencing an app in Safari vs. experiencing the same app natively, I personally go for the app (unless the developers failed to implement a key feature natively). Turning the "write once, use anywhere" paradigm on its head, Facebook has decided to target the "learn once, code everywhere" paradigm. 

I do not personally use Facebook, but for a platform such as Facebook to invest their money and energy in something, I decided to spend a weekend and play around with React. I had also heard talk around the office of this framework, and figured, who doesn't enjoy some new and shiny playtime with a weekend of a new technology.

Purpose

The current drive in client side development seems to be large frameworks that target the entire client side requirements stack. MVC for the DOM (AngularJS, Ember, Meteor). React takes a more pinpointed approach by focusing on rendering and event-handling of client side UI components. This frees (or burdens) the developer with the opportunity (and responsibility) to select other specialized libraries to handle the rest. For some, depending on the developer's experience, OCD level, and code-management-discipline, this can either be hitting the lottery or the first step towards O&M hell. Lets take the positive side of things and just say that it provides more flexibility to decide what technology is best for a product and team. The programmatics of how the code base is managed, outside of your React components, is for the other guy to worry about (for now). 

Advantages

  1. Declarative over Imperative - Instead of taking the event driven approach of when an event happens to a element, make something else change or update another element, React's architecture is based on the idea that you declare components which define a mapping between a state and desired UI. You write code that declares if something is in a state of X, then the UI/component reflects X, instead of when this happens, make this happen. With React, you get to deal with the what _instead of the _what _and _how. Because you stop worrying about how (through events), the code is somewhat easier to wrap your head around (especially late on a Friday before happy hour), and because of that it's arguably easier to avoid bugs. Because the mapping is in your face, it's clear when the state is changed as the UI, parent down through children, will reflect the state.

  2. Speed - Compared against raw javascript code and other javascript libraries like Angular and Knockout, React performs as it was engineered, very fast. There other considerations to performance that have to be taken into account (we will talk about JSX in a moment), but it's fast. I read claims that it can hit 60+ FPS on iOS devices, with sub 20ms render times.

  3. Composable - The React components that you build are little self-contained boxes of functionality. These components fulfill a contract interface which defines the inputs (properties), and resulting outputs as callbacks. You can use these interfaces to cleanly nest your components within other components, allowing for theoretically a lot of reuse through projects.

The code

React javascript is that- javascript​. However, differing from most javascript frameworks and libraries to which you are probably accustomed, React provides the option to use an extension called JSX. JSX allows you to code parts of your component code in XML-like syntax, allowing less experienced developers, or even designers, to build React components to some extent. React components build with JSX are, at either execution time or pre-compiled time, turned into javascript calls syntax with which you are already familiar. 

Helpful links before getting started:

  1. React: http://facebook.github.io/react/
  2. JSX transformer extension: http://fb.me/JSXTransformer-0.12.2.js
  3. JSFiddle React playground: http://jsfiddle.net/vjeux/kb3gN/

Here's your typical Hello World, or John.

/** @jsx React.DOM */
var HelloMessage = React.createClass({  
  propTypes: {
     name: React.PropTypes.string.isRequired
  },
  getInitialState: function(){
     return {
        msg: 'World',
        randomStateVariable: 'blog'
     };
  },
  render: function() {
    return <div>Hello {this.props.name}</div>;
  }
});

React.render(<HelloMessage name="John" />, document.getElementById('container'));  

A breakdown of the code:

  1. The /** @jsx React.DOM */ triggers the JSX transformer to transform (shocking, I know) the following code from JSX form to legal javascript syntax.
  2. React.createClass({..}): This is the call to create a new React compatible/capable component.
  3. propTypes: { name: React.PropTypes.string.isRequired }: A hash of properties, passed to the component when being consumed, and any requirements or checks imposed on them. In this case, name is required and it must be a string.
  4. getInitialState: function(){..}: A hash/javascript object declaring the variables for maintaining state. This is optional. If your component doesn't use state, it doesn't need it.
  5. render: function(){..}: The callback which will build the UI component onto the page.
  6. <div>Hello {this.props.name} </div>: JSX syntax declaring that this React component will render a DIV element, with text comprised of Hello and the value of the name property passed to this component.
  7. React.render(<HelloMessage name="John" />, document.getElementById('container'));: This is the call to instantiate a HellowMessage component. name, set to 'John', is one of the properties being passed to the component. It is referenced in #6, through the 'props' object. The second parameter in the React.render call is where this component will render its content. In this case, it is going to be rendered into an element with id 'container'.

There are many, many, many more callbacks that are provided for React objects, like those that hook into pre-create of the object. I will not go into them here, but just check out the documentation as they are easy to understand.

JSX translation of the code

The code above, when transformed by the JSX extension looks like this:

var HelloMessage = React.createClass({displayName: "HelloMessage",  
  propTypes: {
     name: React.PropTypes.string.isRequired
  },
  getInitialState: function(){
      return {
          msg: 'World',
          randomStateVariable: 'blog'
      };
  },
  render: function() {
    return React.createElement("div", null, "Hello ", this.props.name);
  }
});
React.render(React.createElement(HelloMessage, {name: "John"}), document.getElementById('container'));  

The most important thing to take note of in the translation is that the JSX/XML like calls made are translated into legal javascript function calls.

  1. render: function(){ return <div>Hello {this.props.name} </div>; }
    becomes render: function(){ React.createElement("div", null, "Hello ", this.props.name); }
    1. You can see where the element is transformed into a call to React's createElement, with a set of parameters. 
      1. 'div': The element type
      2. null: Element attributes
      3. "Hello ": The first part of the content
      4. this.props.name: The second part of the content
  2. React.render(<HelloMessage name="John" />, document.getElementById('container'));
    becomes React.render(React.createElement(HelloMessage, {name: "John"}), document.getElementById('container'));``​
    1. You can see where the element is transformed into a call to React's createElement, with a set of parameters.
      1. HelloMessage: The class type being instantiated
      2. {name: "John"}: Hash of properties being passed
      3. document.getElementById('container'): Already valid javascript​- passed as the containing parent.

Implications of JSX

There are some implications of using JSX in your React component code. There are also some mitigation to those implications, trade-offs and decisions you and your development teams are going to have to make.

  1. JSX code, not being valid javascript, is not afforded the same conveniences of valid javascript:
    1. No IDE formatting, typically.
    2. No or very limited browser debugging.
    3. No linting.
    4. No minifying.
  2. JSX code, if transformed just-in-time (via JSXTransformer) incurs a significant performance penalty.
  3. It is easier for the developer to code, in general, because the developer can code elements very close to XML or HTML, and leave the transformation to legal javascript to JSX.

Mitigations of JSX performance issues

If you want to use JSX and want to mitigate the performance hit when using the just-in-time JSXTransformer, you can use a JSX transformer during your build process. The JSX transformer I used this weekend is the node react-tools package. After installing react-tools, you can transform your React components during the build and deployment of your application. During development, you can start the jsx react-tools process and have it watch your component directory, and it will proactively transform your React component files.

Ruby on Rails integration

Because of my affinity towards Ruby on Rails, I feel I would be doing a disservice if I did not mention this blog for integration of React with Ruby on Rails, via the react-rails gem.

Wrapping it up

Now I know client applications, without the interaction of some kind of web service or server app, can be quite boring. I did not touch on interactions with server side or web services here, but between that capability and the other capabilities of the framework, there is plenty to consume many more weekends. I hope that this quick introduction to React provides some insight and clarity into what React provides, how it provides it, and what, as a developer, you can expect as an experience in developing your client side experiences with it. Facebook's decision to bring React to the native mobile platform environments will help ensure React continues to evolve and improve, so an investment of your time in learning can be seen as considerably safer. At least it'll help bridge the time until new and not-anything-like-the-old Angular 2.0 shows up..

Questions, comments? @leechris or [email protected]