Adam Innes · Blog

React Is Open Source: A First Look at Facebook's UI Library

· 6 min · javascript, react, web development

A week ago today, on May 29, Facebook pushed a commit titled “Initial public release” to its React repository on GitHub and tagged it v0.3.0. The README describes React as a JavaScript library for building user interfaces, and it ships under the Apache 2.0 license. The project’s Common Questions page says the Instagram website is built entirely in React and that Facebook is using it more and more, including in the commenting plugin you see all over the site.

React takes an unusual approach to keeping the DOM in sync with your data, so it’s worth a close look. The npm package for the command line tools has already picked up a couple of small point releases, but everything here sticks to what the 0.3.0 docs describe.

Components with a render method

The unit of everything in React is the component. You define one with React.createClass, passing an object that has a render method, and render returns what the component should look like. According to the API reference, it returns a single child, which can have as deep a structure under it as you like. You never call new yourself. React constructs the backing instance for you.

Inside render, the data a component was given lives on this.props. To put a component on the page you call React.renderComponent with the component and an existing DOM node to render into.

There are two kinds of components. Composite components are the ones you write with createClass. DOM components like div and span live on React.DOM and correspond to browser elements, but the docs are careful to say they aren’t DOM elements. Their property names are camelCased, you write className and htmlFor instead of class and for, and style takes an object rather than a string.

JSX is optional

The first thing people will notice in the examples is what looks like HTML sitting in the middle of JavaScript. That’s JSX, and the JSX Syntax page calls it recommended but not required. It’s a straight syntactic transform: <Nav color="blue" /> becomes Nav({color:'blue'}), and children become extra arguments. The docs point out that JSX neither provides nor requires a runtime library and doesn’t change the semantics of JavaScript. A /** @jsx React.DOM */ comment at the top of the file tells the transform to look up lowercase tags like div on React.DOM, so you don’t need a variable for every element.

There are two ways to run the transform today, and the Getting Started guide covers both. For trying things out, you include JSXTransformer.js on the page next to React and put your code in a <script type="text/jsx"> tag, and the conversion happens in the browser. For anything real, you install the react-tools package from npm globally, which gives you a jsx command that compiles a source folder into plain JavaScript, and then the page only needs React itself. My advice is to treat the in-browser transformer as a sandbox and precompile anything you ship, since there’s no reason to make every visitor’s browser do that work.

Re-render, then diff

Pete Hunt’s post on the React blog, Why did we build React?, published today, lays out the model. In a typical JavaScript app you work out what data changed and then imperatively poke at the DOM to match. When a component first mounts, React calls render, which produces a lightweight representation of the view, turns that into a string of markup and injects it into the document. When the data changes, React calls render again, diffs the new return value against the previous one, and applies the minimal set of changes to the DOM. The value render returns is neither a string nor a DOM node, just a description of what the DOM should look like, and the React team calls this process reconciliation. The README puts the same idea in one line, saying React minimizes interactions with the DOM by using a mock representation of it.

The practical effect is that you write render as if you were drawing the component from scratch every time, and React works out the patch. The Component Data docs walk through a small like link and note that when it’s clicked, only the link’s text content is actually mutated. Hunt says the re-render is fast enough (around 1ms for TodoMVC) that you don’t need to declare data bindings at all. Event handlers get similar treatment. They look like they’re attached inline, but the Event Handling page explains that React adds one top level listener per event type and simulates capturing and bubbling itself.

Props, state, and which way data moves

The Component Data page splits a component’s data into two kinds. Props are passed in by whoever creates the component. State is private and managed by the component itself. You describe the starting state by returning an object from getInitialState, read it from this.state, and change it only by calling setState, which merges the object you pass into the current state. Whenever props or state change, render runs again, and the docs say render shouldn’t depend on anything besides those two.

The tutorial describes props as immutable and owned by the parent, and the docs say never to mutate this.props or this.state directly. The API reference adds a detail that’s easy to trip over: setState doesn’t change this.state immediately but queues a pending transition, so reading this.state right after calling it can give you the old value.

So data moves in one direction. A parent keeps state and hands pieces of it down as props, and children render from those props. When a child needs to tell its parent something happened, the parent passes a function down as a prop and the child calls it, which is how the tutorial’s comment form reports a new comment back to the box that owns the list.

A tiny component on the 0.3 API

Here’s a small water tracker that uses both props and state. It only uses APIs documented in the 0.3.0 release.

/** @jsx React.DOM */
var WaterButton = React.createClass({
  render: function() {
    return <button onClick={this.props.onDrink}>{this.props.label}</button>;
  }
});

var WaterTracker = React.createClass({
  getInitialState: function() {
    return {glasses: 0};
  },
  handleDrink: React.autoBind(function() {
    this.setState({glasses: this.state.glasses + 1});
  }),
  render: function() {
    var left = Math.max(this.props.goal - this.state.glasses, 0);
    return (
      <div>
        <p>{this.state.glasses + ' of ' + this.props.goal + ' glasses, ' + left + ' to go'}</p>
        <WaterButton label="Had a glass" onDrink={this.handleDrink} />
      </div>
    );
  }
});

React.renderComponent(
  <WaterTracker goal={8} />,
  document.getElementById('tracker')
);

WaterTracker owns the count and passes a label and a callback down. WaterButton knows nothing about glasses and just calls whatever onDrink it was given. Each click calls setState, render runs again, and the diff finds that only the paragraph’s text changed.

The React.autoBind wrapper matters in this version. Methods on a component aren’t bound to it automatically, so passing a plain this.handleDrink as a handler would lose this. The Event Handling docs show two fixes. You can call .bind(this) inside render, but that creates a new function on every render. React.autoBind binds the method once when the instance is created, which is why it’s the one I’d use.

Markup in my JavaScript?

I think this is where a lot of developers will balk. We’ve spent years learning to keep HTML in templates and behavior in scripts, and a render method full of angle brackets looks like it throws all of that away.

Hunt’s post makes the case directly. Templates limit you to whatever abstractions the template language gives you, while React uses JavaScript to generate markup, so you have a real programming language for building views. He argues that keeping markup together with the view logic that drives it makes views easier to extend and maintain, and that because React understands markup and content, there’s no manual string concatenation and so less surface area for XSS. He also mentions that designers regularly contribute React code written in JSX.

My view is that the old separation was mostly between file types, not between concerns. A template and the code that updates it are already tightly coupled, they just live in different files and fall out of sync quietly. A component that puts the two side by side is at least honest about that coupling. And if the syntax is the part that bothers you, JSX really is optional, and the plain function calls it compiles to are perfectly readable.

A few practical things are worth knowing before you try it. The Common Questions page says React supports the latest two versions of Chrome, Firefox, Safari and Internet Explorer, and IE8 works if you add ES5 shims. This is also a 0.3 release, so I wouldn’t be surprised to see some of these APIs change as more people outside Facebook start using it.

The takeaway

React’s pitch is simple to say and surprisingly different in practice: write components that describe what the UI should look like for a given set of props and state, and let the library figure out how to change the DOM. JSX is the part everyone will argue about, but the idea underneath it, re-rendering a lightweight description and applying only the difference, is the part I’d pay attention to. Grab the starter kit from the Getting Started guide, build one small component, and see whether not writing DOM update code changes how you think about the rest of your app.

← all posts