Remarkable React

August 26th, 2013. Tagged: facebook, JavaScript, performance, react

I gave a talk about React at BrazilJS few days ago. The "slides" are here. In this post I'll go over what I said (more or less) at the beginning of the presentation. I hope to follow up with some more code.

Disclaimer: I work at Facebook. But these are my thoughts. In fact, I may have gotten some things wrong. I was in no way involved in building React, these are opinions of a developer trying to build a thing or two with React.

React is a new, open source library from Facebook and Instagram. It's a library for building user interfaces for web applications.

Active Apps vs. Passive Pages

It's important to make the distinction between web applications and web pages. This is because React breaks a common best practice - the ever-so-famous separation of concerns: content, presentation, behavior. Pages are mostly content, static HTML content, with some styling from CSS and a bit of JavaScript behaviors here and there - maybe some form validation and other simple modifications of the content.

The applications are different. The application data and content changes constantly - from user actions, from new data coming from the server or simply with the passage of time.

Damn DOM

On the web we build web applications using the DOM. Not that we wanted to and not that the DOM was designed for todays applications (after all it has a "document" in the title). It's just something we ended up with. So today we're using DOM and our applications need to keep modifying the DOM all the time, over and over again, to create those rich experiences.

And we all have a love/hate relationship with the DOM. On one hand it's easy and familiar and seems to do the job.

On the other hand the DOM API is verbose. We spend a lot of time just hunting for the nodes we need to modify (like getElementById, getElementsByTagName). Then once we have found the nodes, we start doing cycles of createNode/appendChild to update those nodes.

Also DOM modifications are slow. The browser needs to repaint and reflow, which are costly processes, so we need to be careful when touching the DOM. Often recommended practices are to not read from the DOM all the time, to batch DOM operations and so on.

Then there are the event handlers - you need to make sure you cleanup event handlers attached to nodes you remove, to prevent memory leaks.

This is where React comes in to offer an simpler way of building UIs. React lets you build your application using components that know how to render some data. When data changes, components update automatically in a very efficient way, only where necessary. And all the job of attaching and detaching event handlers is taken care of for you. Also efficiently - using delegation.

Terrible tables

Think about the last time you needed to create a table from an array of data.

var table = document.createElement('table');
var tr = document.createElement('tr');
var td = document.createElement('td');
var text = document.createTextNode('some data');
td.appendChild(text);
td = document.createElement('td');
text = document.createTextNode('some more data');
td.appendChild(text);
tr.appendChild(td);
table.appendChild(tr);
// .....

Gets pretty annoying pretty quickly.

And then one the table cells happens to be a link. Oh, man, there we go again...

createElement('a'), setAttribute('href', 'http://'), createTextNode, append to the link, append to the td, append to the tr...

Then a single letter in a single table cell changes. What you're going to do?

  • Do you keep references to all nodes, to all objects? That's insane.
  • Do you traverse the table hunting for the node? Gimme the 3rd cell in the 5th row? This would be often inefficient, remember, the DOM is slow.
  • Do you rebuild the whole table? This is probably the only sane option. It will be inefficient (reflows, repaints of a big chunk of DOM). And what if there were event handlers on the cells? Or an input that user has typed in already.

In React's case you say:

  • I have this little component here called Table with Rows and Columns children
  • I have an array of data
  • Deal with it!

Then something in the array of data changes? Here's the data, React, my dearest - deal with it.

Internal ideas

So how does exactly React deal with it internally? Two crazy ideas - virtual DOM and synthetic events.

You define you components in React. It builds a virtual DOM in JavaScript land which is way more efficient. Then it updates the DOM. (And "virtual DOM" is a very big name for what is simply a JavaScript object with nested key-value pairs)

Data changes. React computes a diff (in JavaScript land, which is, of course, much more efficient) and updates the single table cell that needs to change. React replicates the state of the virtual DOM into the actual DOM only when and where it's necessary. And does it all at once, in most cases in a single tick of the requestAnimationFrame().

What about event handlers? They are synthetic. React uses event delegation to listen way at the top of the React tree. So removing a node in the virtual DOM has no effect on the event handling.

The events are automatically cross-browser (they are React events). They are also much closer to W3C than any browser. That means that for example e.target works, no need to look for the event object or checking whether it's e.target or e.srcElement (IE). Bubbling and capturing phases also work cross browser. React also takes the liberty of making some small fixes, e.g. the event <input onChange> fires when you type, not when blur away from the input. And of course, event delegation is used as the most efficient way to handle events. You know that "thou shall use event delegation" is also commonly given advice for making web apps snappy.

The good thing about the virtual DOM is that it's all in JavaScript land. You build all your UI in JavaScript. Which means it can be rendered on the server side, so you initial view is fast (and any SEO concerns are addressed). Also, if there are especially heavy operations they can be threaded into WebWorkers, which otherwise have no DOM access.

Fine final

Go check React out. You might like what you see. You can also read some more on "why React" here.

Comments? Feedback? Find me on Twitter, Mastodon, Bluesky, LinkedIn, Threads