My own React vs. Angular

TL;DR

Today I am comparing the still new, pretty hype React + Flux front-end framework to the very popular Angular. I reach the conclusion that the Facebook one has a cleaner architecture, performs better and is easier to learn than its opponent. Hopefully I will make a point with the following, … at least to those who don’t have an opinion yet!

It’s all about the data babe

While coding a SPA, there are two new challenges that need to be addressed:

  1. How to keep the data up-to-date with the server
  2. How to maintain the data coherent within a page

Cut it short, I am not going to discuss the first one here. The reason is React and Angular pretty much deal with it the same way: they (barely) don’t, leaving the job to other libraries, like Restangular or Backbone, among others. Thus, discussing it here would be off-topic.

Let’s dive into the second challenge instead.

How to maintain the data coherent within a page during browsing?

Indeed, after the user has been browsing your app for half an hour without page reload, you can’t afford to display incoherent information like a log in button at the bottom while loggued in at the top and a different number of likes in the sub-menu than on the main page, right?

A practical example

Let’s take an example from an app I built with React: Novatu.be Like Button

Like Button

What happens when the user clicks the button? 4 things:

  1. The Like Button goes into an active state, and changes its text from ‘Like’ to ‘Liked’
  2. The Like Counter of the current track is updated from 0 to 1
  3. In the tracklist, the Like Counter of the track is updated from 0 to 1
  4. In the tracklist, the playing track goes into a liked state, adding an heart on it jacket

Here is screenshot after the user clicked the button:

After the button click

Now, let’s discuss the different possibilities we have to handle those changes.

100% hand-coded: jQuery

Using jQuery, coding this behavior can quickly become a mess. Let’s give it a try:

With the initial HTML:

<div class="current-track">
  <button class="btn-like">Like</button>
  <h1>Track Title - Track Artist</h1>
  <span class="nb-likes">0</span>
</div>
<ul class="tracklist">
  <li class="active">
    <img src="X"/>
    <span>Playing Track Title - Playing Track Artist</span>
    <span class="nb-likes">0</span>
  </li>
  <li>
    <img src="X" />
    <span>Track Title - Track Artist</span>
    <span class="nb-likes">0</span>
  </li>
  <li>
    <img src="X" />
    <span>Track Title - Track Artist</span>
    <span class="nb-likes">0</span>
  </li>
</ul>

We would have to write the following JS:

$('.btn-like').on('click', function(e) {
  $.post(url, {state: $(this).hasClass('active')}).then(function(data) {
    var newTotal = data.nbLikes;
    $('.current-track .nb-likes').html(newTotal);
    $('.tracklist li.active .nb-likes').html(newTotal);
    if (data.liked) {
      $('.btn-like').addClass('active');
      $('.btn-like').html('Liked');
      $('.tracklist li.active img').addClass('liked');
    } else {
      $('.btn-like').removeClass('active');
      $('.btn-like').html('Like');
      $('.tracklist li.active img').removeClass('liked');
    }
  });
});

Not only is it complicated and hard to read/maintain but it is not DRY: the ‘Like’ content is repeated in the HTML and in the JS. In addition, there is no guaranty that the data is synchronised with the server. There is no way to prevent another JS script to add the active class to the .btn-like button.

That said, this code only tackles one like button. Imagine if we were to handle comments, replies, etc.

That’s when frameworks come to the rescue.

The component architecture

Angular and React, like most front-end frameworks, tackle this issue by creating isolated components. Instead of having to control a full web page with a wide DOM, we’d rather manipulate smaller boxes with limited input and output, right?

That’s a component. Think of a function that has a few parameters input, and has the capacity to output, well, the HTML that will be displayed on the page.

A Components

Back to our former example, we could isolate different parts of our app like so:

1. Like Counter

Hence the Like Counter can render by simply having the nbLikes parameter:

<!-- LIKECOUNTER COMPONENT -->
               |-----------|
  nbLikes ---> |LIKECOUNTER| ---> <span class="nb-likes"></span>
               |___________|

2. Like Button

The Like Button is a little trickier: it needs the isLiked parameter, but also to know what to do onClick:

<!-- LIKEBUTTON COMPONENT -->
               |------------|
  isLiked ---> |            |      <button class="btn-like">Like</button> // if isLiked == false
  onClick ---> | LIKEBUTTON | ---> <button class="btn-like" class="active">Liked</button> // if isLiked == true
               |____________|

3. Current Track

Since it is possible to compose components together, the Current Track component would describe as so:

<!-- CURRENTTRACK COMPONENT -->
                  |--------------|
  nbLikes ------> |              | ---> <div class="current-track">
  isLiked ------> | CURRENTTRACK |        <LIKEBUTTON isLiked onClick>
  onClick ------> |              |        <h1>Track Title - Track Artist</h1>
  currentTrack -> |______________|        <LIKECOUNTER nbLikes>
                                        </div>

You got it, right?

In a schema, the whole decomposition would be:

Components Web Page

This component-oriented architecture is common to Angular and React.

So what’s the difference between the two frameworks? Answer:

The difference lies in how the data flows among the components.

The Angular double data-binding

Angular is famous for having the double way data-binding. If it is changed in a component, it will tell the other connected components. On a schema, here are the different channels of communication for the data:

The Angular Way of flowing the Data

Here’s how things go when the user clicks the Like Button:

  1. If the LIKEBUTTON component is clicked, it is the component itself that is in charge of talking to the server, and receiving the result: {isLiked: true, nbLikes: 1}
  2. Once received, the LIKEBUTTON will tell CURRENTTRACK about the change.
  3. CURRENTTRACK will dispatch to LIKECOUNTER and the BRAIN
  4. The BRAIN will tell the TRACKLIST
  5. The TRACKLIST will inform the concerned TRACK
  6. The TRACK will inform the COUNTER
  7. It is only when every component received the value that the component are re-rendered and the UI is updated.

On a schema:

The Angular Way of flowing the Data in the example

The React + Flux architecture:

This time, we have a different architecture based on something you may have heard of along with React: Flux. The idea of Flux is that the whole business logic and data should lie in the Brain, then the components only access the data in a read-only mode.

So here’s what happens when the user clicks the like button:

  1. When the button is clicked, it has been wired to call a method in the BRAIN, called likeButtonClicked
  2. This method is in charge of making the API call to the server, and updating the BRAIN accordingly.
  3. The BRAIN tells its children component that he has new value
  4. CURRENTTRACK and TRACKLIST tell their children components that they have new value
  5. The TRACK which corresponds to the CURRENTTRACK knows it has changed values and tells its COUNTER to update
  6. Those modifications are reported to the UI which is updated if it is ready to do so

On a schema:

The React Way of flowing the Data in the example

Conclusions

Angular’s very advertised double-way data-binding has a great advantage : things are binded together automagically. Less questions to ask oneself, less behavior to describe: everything’s plug and play.

But this abstraction comes at a cost:

  1. React has a better architecture
  2. React has better performances
  3. Angular is harder to learn

1. React has a better architecture

Having components to read-only the data from a single source dramatically reduces risks of incoherence, which is what we were trying to achieve a first, remember?

Besides, I find it easier to have all the business logic and data in the same place. If someone needs to use this code, he will definitely find it. In Angular you’d have quickly duplicated methods that do component specific behavior, like the API call on button click.

2. React has better performances

When Angular recalculates the values in every component, it is called a $digest cycle. Since we have double-way data binding, it is very often that the following occurs:

COMPONENT1 parameter_x changes
=> COMPONENT2 parameter_y needs to be recalculated
=> COMPONENT3 parameter_z needs to be recalculated
=> COMPONENT1 parameter_x needs to be recalculated because it depends on parameter_z
=> and so on and so forth until all parameters_x, parameters_y, parameters_z stop modifying each other...

If those calculation are expensive - and they eventually will be - recalculating the same things even 2 times is a waste. With React, we have full control on when the components should be updated so we can be 100% sure it will only occur when necessary. And since the parameters are read-only, there are no chances that a children component parameter influences its parent one.

There is another situation where React performs better than Angular. If the $digest cycle is super fast in Angular, then the DOM will be updated accordingly. But updating the DOM is a relatively expensive operation too. So it can occur that the browser is still rendering something that is already obsolete in the Angular world. With React, the smart Facebook guys created a virtual DOM which is fast to update, and which reports its modifications to the actual DOM on a frequency adapted to what the browser can hold. If a state was too short living to be rendered in the DOM, it never will.

3. Angular is harder to learn

Eventually, while Angular’s learning curve is famous for being steep, I found React very quickly accessible. If you are curious, read the getting started tutorial, and you will definitely be good to go within few hours, especially after having read this! :-D