Reacting to React

You must have heard all the buzz around React and more recently around React Native. Open-sourced by Facebook, they bring an alternative design to an already crowded web development ecosystem. They could also be an interesting addition to frevvo’s technology stack so let’s take a closer look.

React’s direct precursor originated in Facebook’s Ads organization as a custom version of PHP, called XHP. XHP helped minimize Cross Site Scripting (XSS) attacks by extending PHP with an embedded XML syntax so that programmers wouldn’t have to manually scrub data when generating markup. The embedded HTML markup was then desugared into plain PHP calls to construct markup programmatically. For better or worse, this meant that no external template engine was needed: it was all done in PHP. In many ways this is no different than what ECMAScript for XML (E4X) tried years back for Javascript (and was dropped for good reasons), except it was in PHP and proprietary to Facebook.

Here is what XHP looks like:

<?php
if ($_POST['name']) {
?>
    <span>Hello, <?=$_POST['name']?>.</span>
<?php
} else {
?>
    <form method="post">
    What is your name?<br>
    <input type="text" name="name">
    <input type="submit">
    </form>
<?php
}

And it didn’t take long before the idea of porting this XHP to Javascript came along. After all, dealing with dynamic UIs and the continuous rount-trips to the server are clearly a problem for Facebook. So this was the start of React: an API for creating DOM nodes and a custom JSX syntax for embedding XML in Javascript.

As an aside, what is the difference between JSX and E4X? Basically, JSX is just syntactic sugar and translates XML syntax into function calls. On the other hand, E4X was tied to a specific and internal representation that had to be converted to and from to interact with the rest of the app. E4X was also closer to XML whereas JSX is closer to Javascript. One example is the difference in namespace handling: in E4X every XML element had a namespace, like XML. JSX, on the other hand, uses Javascript to deal with namespaces i.e. each node is represented by a unique string across your program and you have all of Javascript features (functions, variables, closures, etc) at your disposal to use and reuse these views.

Fine, JSX is a better version of E4X, but that is not the most interesting aspect of React. The interesting bit is the Virtual DOM. Everyone knows that manipulating DOM nodes is expensive, should be minimized and properly ordered to avoid un-necessary layout recalculations. The Virtual DOM avoid these problems by constructing a Javascript intermediate representation for the whole UI that is completely detached from the DOM. It is React’s responsibility to compare this Virtual DOM to the actual browser DOM and compute a minimum set of updates needed. React calls this step the Reconciliation. These updates are then batched, pruned, ordered, and executed in one shot in specific intervals. Although comparing the difference between two trees is known to have O(n3) complexity, React was able to reduce this complexity to O(n) based on specific heuristics. The end result is a fast and less error prone solution.

ditaa-b0ba6bda71b2f0d371adc1b633b075ac

React Reconciliation

One consequence of React’s design is that the components generating markup can be truly stateless. They take new data as inputs, generate a new Virtual DOM as the output, and the UI is efficiently updated. In essence this is not much different than how a 3D engine game loop works. If you want to undo a change, just re-render the UI using the previous version of the data and React will make sure that the DOM is updated accordingly.

Here is an example of what a React component looks like (assume you can replace JSX markup with plain Javascript calls, if that is not your thing or want to avoid an increase in tool-chain complexity):

var HelloMessage = React.createClass({
  render: function() {
    return <div>Hello {this.props.name}</div>;
  }
});

React.render(<HelloMessage name="John" />, mountNode);

And here is what JSX compiles to:

var HelloMessage = React.createClass({displayName: "HelloMessage",
  render: function() {
    return React.createElement("div", null, "Hello ", this.props.name);
  }
});

React.render(React.createElement(HelloMessage, {name: "John"}), mountNode);

Here is an example of composing multiple view components (note that composition is done using just Javascript: no hidden complexities or framework magic):

var Avatar = React.createClass({
  render: function() {
    return (
      <div>
        <ProfilePic username={this.props.username} />
        <ProfileLink username={this.props.username} />
      </div>
    );
  }
});

var ProfilePic = React.createClass({
  render: function() {
    return (
      <img src={'https://graph.facebook.com/' + this.props.username + '/picture'} />
    );
  }
});

var ProfileLink = React.createClass({
  render: function() {
    return (
      <a href={'https://www.facebook.com/' + this.props.username}>
        {this.props.username}
      </a>
    );
  }
});

React.render(
  <Avatar username="pwh" />,
  document.getElementById('example')
);

Since the Virtual DOM is nothing more than an efficient browser DOM abstraction, it wouldn’t be complete without a way to handle dynamic DOM events. Here, React provides a full set of synthetic HTML5 events on top of the DOM events. React components will interact with these synthetic events and the runtime will efficiently adapt the DOM event registration, firing, and bubbling under the covers. This also means that React also runs on older browsers such as IE8 without any problems: the Virtual DOM adapts the older event model into the synthetic one.

React, however, is not a full Javascript UI framework. From an Model-View-Controller (MVC) perspective it corresponds to the view layer and the unit of abstraction is the React component, which is nothing more than plain-old Javascript objects that can be rendered based on a set of inputs. There is no external template engine since Javascript is your engine constrained only by JSX or the Virtual DOM APIs (or, in other words, as constrained as a dynamically typed language can be here). Components can be developed in isolation and composed into composite views.

There are other interesting and obvious benefits of this design. For example, it is possible to test the UI on the server with node.js or even Java’s embedded Javascript engine and without the need for clunky solutions such as PhantomJS (this a specially interesting propery since frevvo renders PDFs on the server). Since the HTML5 markup can be completely generated on the server you can also cache the initial HTML. Users will have a nicer experience since the UI will be rendered very quickly and as soon as the UI Javascript is loaded by the browser, it will diff the existing DOM and just attach the event handlers assuming the initial data didn’t change. Even, if the initial data did change, things will work as expected. Finally, it is also possible to render to SVG, VML and Canvas.

In general, React provides a good power-to-weight ratio since it keeps the API surface simple and flexible by reusing Javascript while it removes many of the complexities from the programmer without sacrificing performance for most cases. As a bonus, it also enables additional server side processing that is quite important for frevvo specially with respect to caching and PDF generation. There are plenty of resources out there with many more details, but one you could start with is this by Pete Hunt.

In a following post, I will take a look at React Native and how it can potentially enable a more cost effective and sane solution for supporting multiple native mobile platforms, specially for smaller companies.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: