If you are a computer scientist this talk will be fascinating as it documents the steps to build an effective “diff-ing” algorithm that understands when the state tree has changed. Christopher showed how initial approaches had an O(n^3) algorithmic complexity. Anyone that has ever interviewed for a computer engineering position knows that this is a high cost algorithm to be avoided with anything other than tiny data sets. The presenter noted that with a large web application with 10,000 DOM nodes, this would mean diff’ing the tree would require 17 minutes on a 1 GHz CPU. As Facebook engineers worked further on ReactJS they were able to optimize the algorithm to first achieve O(n^2) complexity, a huge improvement, but then were able to achieve O(n) complexity by using a hash map of DOM elements containing unique keys. This part of the talk was a fascinating entry point into the real CS fundamentals underlying this lovely library.
Knowing the steps used to achieve this algorithmic complexity helps explain why the library has the interface it does. ReactJS relies on a “batch” step and “pruning” step when determining what to render, steps to which your application can offer hints, and understanding the algorithm behind the scenes made lightbulbs go off in my head as I finally got why it worked the way it does. There is a learning curve with ReactJS in that you typically need to marshal data back and forth between views and models which Facebook has built to handle for you ( AngularJS revolutionized this step). The API to do this in ReactJS makes more sense when you understand why it asks you to provide hints at the times it does and this talk clarified a lot for me.
In essence, the ReactJS interface is different than other js libraries which are more imperative, meaning you tell them to change the DOM directly. Jquery is like this. ReactJS is more like: here is my state, and here is how you should interpret my state and how it will change. Now, I can sit back and let ReactJS handle the expensive and complicated task of making this visible to the user in the browser.
Christopher also mentioned a very exciting framework called “Om” from David Nolan written in ClojureScript that wraps the ReactJS library. Because Om uses immutable data structures (a feature of Clojure and derivatives like ClojureScript) Om can optimize the “shouldComponentUpdate” method inside of ReactJS and provide the proper hints automatically to applications so that the ReactJS algorithm most efficiently re-renders the DOM. Implementing undo in an application like Om is trivial, as David notes, and asks that we consider how we could do this in other JS libraries. ReactJS is a solid foundation to write interesting libraries upon.
Lastly, Christopher spoke about a performance optimization technique that comes free with ReactJS. If your application uses ReactJS, you can use the integrated performance monitoring tools inside ReactJS to analyze which parts of the application are incorrectly subjecting the application to re-rendering. Simply call “perf.printWasted()” inside your application and you’ll see an analysis of places where your application wasted render cycles because ReactJS can tell if a render was called but no state changes were made. You can then hint to your application that it should not do this, improving responsiveness. I’m not aware of other frameworks that are smart enough to tell you when the code is incorrectly written and what to do about it.
Feature image via Flickr Creative Commons.