Cole Williams
8 min readNov 26, 2016

Why React Is Awesome At Scale

***This post only compares using React vs vanilla JS or jQuery. It does not compare other frameworks.***

Effectively managing state transitions and mutations of your UI is essential for any front end engineer. Nowadays, as user interfaces gain more functionality and become more data driven, you (and other non-front end engineers) need to be able to efficiently reason about the state of your application. I believe that Facebooks React.js library is the best and most cost effective way of doing this. In this post I’ll show you why.

And as your application scales, React will maintain your UI at O(N) complexity. I’ll show you why I think its

Say you’re building an application that allows messaging. So you build a message Icon and when you click it, it shows you all your read and unread messages. Like facebooks:

Facebooks message component

For this example, we’ll be using this icon instead :

Our message component for this example app

Your message component will receive incoming message updates from the server, and modify the display of the message icon as needed.

In this example, I’ll show you a typical, imperative way of managing the message icon state with vanilla JavaScript , and the declarative way with React. (In short, imperative programming focuses on what precise steps the computer should take, i.e. how it should complete a task. In Declarative programming you tell the computer what it should do, and how it completes the task is abstracted away. React is a declarative library. More about imperative vs declarative here)

For now, lets say the message icon has 3 possible states: No messages, between 1–999 messages, and more than 999 messages(or 999+) in which we’ll render the background yellow to draw more attention to message icon.

I used draw.io to create a mock message icon. Ugly, I know, but it will suffice for the purpose of this post.

The 3 states of the message icon

Lets say we start at the stage with zero messages in our inbox (Oh, how nice that must be). Then the user receives 3 messages, triggering a state change in the message icon and alerting the user that they have 3 new messages (middle icon).

When the shift from zero to 3 messages happens, we need to add the blue marker which will display the quantity of messages.

First state transition from no messages -> 3 messages

These are imperative operations. We’re telling the computer exactly what to do to our message icon and modeling state transition from one state to the next state: 1) Add a blue marker. 2) Set the value of this blue marker to ‘3’.

Next, lets show the transition from no messages, to 999+ messages. Again, following the imperative style

Second state transition for message icon

Again, here, we imperatively model the state transition with 3 commands: 1) Add blue marker. 2) Set the marker’s value to 999+. 3) Add a background color of yellow.

Here is what the imperative code would look like for these state transitions.

Code for managing the 3 possible states

Here is what we’re telling the program to do:
- If the quantity of messages is greater than or equal to 999 and it doesn’t have a yellow background, then add a yellow background.
- Else, it must have less than 999 messages. So if it has a yellow background, remove it.
- Then we say if the quantity of messages is strictly equal to zero, and it has a blue marker, remove the blue marker and return, because we no longer need to determine the value of quantity.
- If the interpreter has made it to this point, then we know the value of quantity is less then 999 but greater than 0. So if it doesn’t have a blue marker, add a blue marker.
- We then set the value of the blue marker with the variable ‘value’ using an ES6 ternary operator

This isn’t exactly easy code to read. It’s already becoming difficult to reason about and we’ve only built a very basic implementation.

But some of you are probably asking ‘Why is this so bad? Seems reasonable to me’. Yes, you may be right. But in this implementation, we are determining the state of the message icon by reading directly from the DOM. Which is very expensive. Determining the state of your application by constantly reading from the DOM may at first perform similarly to an application that utilizes a Virtual DOM( like React ). But reading from the DOM can force the browser to perform a reflow of the layout — $$$

Now, here is where things get interesting…

Our current possible state transitions look like this:

Lets add another state to the message icon. An error state. If for some reason the messages aren’t loading properly, we want to display a red exclamation mark, like this:

Error state — 4th possible state for message icon

With this one addition of a possible state, our state transition flow now looks like this:

Potential state transitions with 4th possible state added

The arrows aren’t exact — just for visualization.

Adding a 4th possible state significantly increases complexity. We are assuming an error state can occur at any time and with any quantity of messages. When the error is resolved, the message icon will shift its state back to any one of the 3 non-error states.

The time complexity of this is quadratic — O(N²-N). We have a N possible states, and we can transition to any N-1 state.

  • *Big O for this is O(N(N-1)) === O(N²-N)

As you can see things can quickly get out of hand.

What if a 5th possible state were to be added. Say a ‘loading’ state where the messages are being retrieved from the server. This would increase the complexity of our message icon by a quadratic magnitude. So for every additional state transition, the complexity increases quadratically. Ouch. My head is hurting already and I can hear my old CS teacher screaming at me to refactor.

Don’t worry, THIS IS EXACTLY WHAT REACT SOLVES

Handling these state mutations is hard, expensive, and exhausting. We have to somehow reason about ALL the possible scenarios where state can change. So lets not do it!!!

Ok, but how?

Let React do it:

Handling 4 possible states in React
  • I’m using screen shots from my text editor because I think they are easier to digest than using Medium’s code snippet area

For those completely unfamiliar with React:

  • ignore the render function(This is what React uses to create the component tree which makes up the virtual DOM.)
  • {value} is JSX. I know it looks weird. Just know that the messageIcon will display the variable value.

Really, pay attention to what we are returning(I ommited <div> tags and some best practices so its easier to read for non React-ers), this is a lot easier to reason about. Even if you’ve never seen React before, you can figure out whats happening here fairly easily.

  • Query the database for the messages for this user
  • If there is an error, set value to red exclamation mark, and render that.
  • If quantity is > 999, set value to ‘999+’ or set value to quantity.toString() and render that.
  • If quantity is > 999 and there is no error, set the background color to ‘yellow’. Else, set background color to ‘none’ and render that

All of those conditional statements I wrote in previous code snippets, and if the bullets above are abstracted away by Reacts declarative style. React will run those checks for you on any update to the DOM without reading directly from the DOM, but reading from the virtual DOM. This is the heart of React, their reconciliation algorithm, which runs a diff between the current Virtual DOM and the previous Virtual DOM to update the UI on any change. You can read more about the reconciliation algorithm here.

Instead of us imperatively running tests of conditional statements determined by reading from the DOM to find out if anything has or will change (first part of this post), React does this FOR you. So you can set it and forget it. :)

We’re essentially saying: ‘Hey React, you’re gonna render a messageIcon component with a variable value and a background. You go figure out what the values of these should be’. (Should have chosen a different name for the ‘value’ variable :( ).

Any changes to quantity will cause React to check those values and render the appropriate values to the DOM. This avoids rebuilding the DOM in anyway which saves lots of $$$.

Earlier we saw how complex it can get handling state transitions and mutations with plain JavaScript. React at its core diffs the DOM and performs these transitions for us at O(N) time. The reconciler (module inside of react) will crawl through the DOM nodes from top to bottom and figures out what needs to change(In O(N) time).

Here’s a quote from the React docs:

“ There are some generic solutions to this algorithmic problem of generating the minimum number of operations to transform one tree into another. However, the state of the art algorithms have a complexity in the order of O(n3) where n is the number of elements in the tree.

If we used this in React, displaying 1000 elements would require in the order of one billion comparisons. This is far too expensive. Instead, React implements a heuristic O(n) algorithm”.

At scale, React will maintain this O(N) time complexity for DOM diffing and state transitions. This is powerful. As your application grows you can be certain that your UI (if built with React) will scale efficiently and effectively without having to go back and refactor.

Say you add another 3 possible states for the messageIcon. What would the time complexity of that be without using React?!?!?!

And this is for one single DOM node in our application

If you’re curious about how React does all this, you’ll have to jump into those weeds on your own. However their source code is somewhat beginner friendly if you’d like to take a crack at it.

In my opinion, if you aren’t using React to build out your UI, you’re foregoing significant optimizations and savings.

Cole Williams

JavaScript Engineer. Brain, Earth, and React.js Lover.