We often explore new technologies to help us deliver the best experiences possible. The past year has seen a glut of new reactive frontend technologies like React, Polymer and Angular 2.0 enter developer consciousness. When we investigated React we discovered its disciplined approach to reactive UI construction paired with a realtime backend (such as Meteor) has the potential to create delightful and maintainable apps.

Reactive Templating

Reactive, or declarative templating is a style of user interface (UI) construction that contrasts with the imperative approach championed by libraries like jQuery.

Declarative templating separates UI state, the underlying logical situation of what the user can see, from the layout being viewed (DOM). You declare how the rendering technology should translate your state into the visual elements of the DOM. From then on you simply update the state and the DOM adjusts automatically.

Imperative technology includes state in the DOM. Thus pains must be made to ensure that the DOM state is manually kept up to date. For example, consider the unread email count in Gmail. If Google implemented the unread email UI imperatively, this is what it would look like.

When an email is read, we need to: Change the appearance of the email to indicate that it was read Update the unread count

When we check and find a new email on the server, we need to: Draw it in the UI Update the unread count

When we delete an email, we need to Remove it from the UI Update the unread count



Something as common as an unread count would need to be changed in many places and depend on a variety of states. The complexity of an imperative UI in a realtime system asks for errors and inefficiencies. A declarative rendering framework manages complexity with an internal model of the core state of the page (the list of unread emails) and automatically changes the UI to reflect this model.

Reactivity & Meteor

Despite the fact that reactive UIs make for cleaner, more reliable frontend code, they’re often considered nice-to-have’s for traditional applications. However, modern products built on reactive backends like Meteor are nearly impossible to deliver without reactive frontends.

Meteor is a realtime framework that provides a constant stream of updates to the data model which could come down the wire at any time. In contrast to the user-initiated interactions in the unread email example, Meteor allows any part of our UI state to change at any time to reflect the state of the system. Trying to imperatively reconcile and patch changes to the system would be a nightmare.

Approaches to Rendering

It’s no surprise then that Meteor ships with it’s own reactive rendering frontend: Blaze. There is a key difference in the way Blaze and React work that makes React promising for Meteor projects.

Blaze piggy-backs on Meteor’s dependency tracking system, Tracker in order to keep track of which parts of the DOM correspond to which parts of the UI state. This means when you change state (e.g. delete that email), it can know exactly which DOM elements to modify. Updates flow from the event directly to the nodes that need to change. While this architecture makes it intuitive to understand what will re-render given a change in a basic system, the origin of changes becomes unpredictable in a large interdependent app.

React uses a straightforward system called the Virtual DOM—a tree of React Components, each of which contains its own state and that of its parents, and corresponds to real DOM elements. Updates always flow up the Component Hierarchy, then down to the relevant nodes. When modifying state, the least common ancestors of all elements that care about that state are also modified. This means that a lot of unrelated elements could be altered as a result. However, React’s diff algorithm mitigates unrelated changes from propagating by calculating the minimum possible Virtual DOM alterations necessary to achieve that change in UI state. Only then does it adjust the real DOM.

React’s Advantages

React’s method isn’t as expensive as one might think. Not only is processing in memory via JS much faster than making changes to the DOM; it presents significant advantages.

Simple to Reason About

There are clear rules that govern how data flows and how it affects the UI. The rules are reinforced by the consistent and stringent way components are put together. The result is intuitive frontend logic.

For instance, consider the Leaderboard example Meteor app which we’ve re-coded in React. When the user clicks the “Add 5 points” button, we pass the change back up to the leaderboard component which is the least common ancestor of all elements that care about the player list. The leaderboard component then takes responsibility for updating the players and flowing the data back down to the various components that need to render them. The diff algorithm ensures that it’s done in an effective way. The rigid internal model helps avoid bugs and makes engineers more productive.

Predictable Reusable Components

React’s top-down data flow results in a natural separation of components. It’s designed from the ground up with clear guidelines for how components interface with each other, thus leading to consistent predictable code. Large teams and projects benefit from disciplined modular architecture that makes component reuse natural. A bonus is they are also easier to isolate and test! The first step to true interoperability on the web is true component libraries.

Server-side Rendering

The diff and patch model makes server-side rendering trivial to implement in any stack. Thanks to Meteor’s isomorphic APIs it’s even easier.

if (Meteor.isServer) { var bodyHtml = React.renderToString(<Leaderboard {...props}/>); // return the HTML from a server-side-route } else { React.render(<Leaderboard {...props}/>, document.body); }

The combination here is sublime:

React’s renderToString quite simply outputs a string of HTML, ready to be served to a google bot, or to render to the user immediately.

quite simply outputs a string of HTML, ready to be served to a google bot, or to render to the user immediately. Meteor’s isomorphic APIs mean that in many cases, the definition of <Leaderboard> does not need to change at all!

Checkout Meteor’s leaderboard paired with React. In a later blog post, we’ll show in detail how the process of server-side rendering and hydration can combine in Meteor to get the best possible behaviour for a single page app.

What about performance?

You’d expect that React’s approach of propagating changes down the component tree rather than directly changing the components that care about an update would be wildly inefficient. In a deeply nested version of the animation above, there are many more changing ancestor nodes that would never be touched in the Blaze example. However, as Facebook engineer Christopher Chedeau explains, performance is great due to the Virtual DOM speed and simple heuristics. The key points:

DOM changes are fairly predictable Component trees are never that large

In other words, the DOM is so sluggish that doing work in JavaScript doesn’t even factor into the performance equation.

Conclusion

It’s clear that React can help you build maintainable interfaces that scale. However, it’s not opinionated about how data is moved between server and browser. This is where Meteor shines. Meteor’s approach to latency compensation & automatic data propagation pairs well with React & the Flux architecture. We’ll explore how in a future post.

React is fantastic for managing large reactive front-ends. Meteor is an unparalleled for transporting data in realtime. Combining both gives engineers the tools to craft maintainable cutting-edge interfaces. There’s no better way to build the rich applications modern users demand.

Reference

Meteor Leaderboard in React

React

Meteor

The “offical” React-Meteor package (still a WIP)

Why React?

What is React? by Evented Mind (video)