React vs Angular: Slow rendering with React

AngularjsReactjs

Angularjs Problem Overview


I was doing a comparison of Angular and React and decided to try out a performance test to see how fast a large(ish) list would render in both frameworks.

When I got done with my React prototype with some basic currency formating, it was taking ~2 seconds to render on my fast laptop. With Angular it was barely noticeable -- only when I switched to my phone did it have a noticeable lag.

This was very surprising because I was told that React was supposed to beat the pants off of Angular for performance, but it appears that the opposite is true in this case.

I distilled my prototype down to a very simple app to try to isolate the issue: https://github.com/pselden/react-render-test

In this sample, it's taking almost 200ms to render this simple list after changing the language, and I'm barely doing anything.

Am I doing something wrong here?

/** @jsx React.DOM */
'use strict';

var React = require('react'),
    Numbers = require('./Numbers');

var numbers = []
for(var i = 0; i < 2000; ++i){
    numbers.push(i);
}

var App = React.createClass({
    getInitialState: function() {
        return { locale: 'en-US' };
    },

    _onChangeLocale: function(event) {
        this.setState({locale: event.target.value});
    },

    render: function() {
        var currentLocale = this.state.locale;

        return (
            <div>
                <select
                    onChange={this._onChangeLocale}>
                    <option value="en-US">English</option>
                    <option value="fr-FR">French</option>
                </select>
                <Numbers numbers={numbers} locales={[currentLocale]} />
            </div>
        );
    }
});

module.exports = App;

/** @jsx React.DOM */
'use strict';

var React = require('react'),
    ReactIntlMixin = require('react-intl');

var Numbers = React.createClass({
    mixins: [ReactIntlMixin],

    getInitialState: function() {
        return {
            numbers: this.props.numbers
        };
    },

    render: function() {
        var self = this;
        var list = this.state.numbers.map(function(number){
            return <li key={number}>{number} - {self.formatNumber(number, {style: 'currency', currency: 'USD'})}</li>
        });

        return <ul>{list}</ul>;
    }
});

module.exports = Numbers;

PS: Added an angular version: https://github.com/pselden/angular-render-test

Edit: I opened an issue with react-intl and we investigated and found that there was not that much overhead with using https://github.com/yahoo/react-intl/issues/27 -- it's simply React itself that is slower here.

Angularjs Solutions


Solution 1 - Angularjs

This is definitely an interesting test case.

If you take a look at the timelines, you can see that Angular is finished handling the change event in a mere 20ms. The remainder of the time is spent in layout and repaint.

Angular Timeline

React (using a production build, your repo uses dev by default) takes about 59ms. Again, the rest of the time is spent in layout and repaint.

React Timeline

If you take a look at the CPU flame charts, you can see that Angular appears to be doing a lot less work.

Angular:

Angular CPU Graph

React:

React CPU Graph

React provides a pretty good optimization hook in the form of shouldComponentUpdate that is especially useful when a single instance of a component out of thousands should update and the others should stay the same; it's a technique I use in this demo (try it out in an incognito window; I've found some Chrome extensions make layout/repaint times much higher—for me, adding/removing single elements once the list is 1000 long takes ~13ms, changing the size/color of an element takes ~1ms). However, it does no good when every element needs to update.

My guess is that Angular will be faster at changing most or all of the elements in your table, and React will be quite proficient at updating select entries when using shouldComponentUpdate.

Solution 2 - Angularjs

I'm surprised nobody mentioned PureRenderMixin. It implements shouldComponentUpdate so you don't have to worry about it.

Also, I wonder if React Performance Tools would turn up something useful?

And I'm surprised to hear Angular is faster than React after watching this talk from Ryan Florence.

Solution 3 - Angularjs

We have tried to analyze some of the attributes of our frameworks, of course, this is not the whole list. Below there is a table of consolidated and important, in our opinion, of comparing attributes.

enter image description here

Let’s get some more details:

enter image description here

enter image description here

Although Angular vs React differences are many, they can do the same thing, namely to build client interface. Both have their place. For those peoples who like web development above all interesting is innovative AngularJS approach to HTML.

AngularJS really is a full framework and not just a library, as the ReactJS, but ReactJS has better performance than the AngularJS by implementing virtual DOM. In our opinion, you should use AngularJS if:

  • you plan to carry a lot of unit tests during development,
  • you want a comprehensive solution for your application.

However, two-way data binding is often touted advantage of using AngularJS, but because it is implemented through a series digest, adding too much complexity for certain functions and expressions can lead to deterioration in performance of your applications.

Solution 4 - Angularjs

In this particular case you need to be aware that the state trickles down and so do the DOM updates. What you want to do is create a Price component that stores the locale in its own state and receives a signal (ie channel or flux) to change the locale as opposed to sending the locale prop all the way down. The idea is that you don't need to update the entire Numbers component, just the prices inside. The component might look like:

var Price = React.createClass({
    mixins: [ReactIntlMixin],
    componentDidMount: function() {
        subscribeToLocal(this.onLocaleChange);
    },
    onLocaleChange: function(newLocales) {
        this.setState({locales: newLocales});
    },
    render: function() {
        return <span>this.formatNumber(this.props.number, this.state.locales, {style: 'currency', currency: 'USD'})</span>
    }
});

Solution 5 - Angularjs

In React component, once you call setState, it will trigger the render function immediately. React will mark this component as dirty, and will re-render all the children element inside this component.

It will not render the whole Native DOM elements because of the Virtual DOM, thus it will still create new instances of its children ReactElements, which can lead to extra Javascript memory cost.

To avoid this issue, you need shouldComponentUpdate function which implemented in Component Class. it will executed before Render method. If you find the there is nothing changed right now, for instance in your example, you change the state.locale. You can definitely consider this component need no update. so just return false to prevent the render call.

This is a base solution to solve React performance issues. Try to add "shoudlComponentUpdate" in your Numbers Component to avoid tons of

  • element re-render

  • Solution 6 - Angularjs

    This is an example where all that is changing is one data output. It's not impossible that Angular's two way data-binding simply offers a faster re-render when all that is changing is the display of the bound data.

    React does not promise that its renders are faster than any other framework under all circumstances. What it does offer is the ability to handle ~arbitrarily complex DOM updates in very efficient manner, and offer a variety of lifecycle methods (e.g. componentWillReceiveProps, componentDidUpdate, in addition to the afore-mentioned shouldComponentUpdate) to let you fire callbacks on those events and control how and if they should happen. Here, there's very little to optimize, because all you are doing is changing 2,000 text displays.

    edit: To clarify, React is useful in doing more complex DOM manipulations because it's virtual DOM algorithm allows it to choose the minimal set of DOM operations necessary to update your DOM. That's still a lot of work to do when all that needs to be happening is 2000 instances of some text changing.

    Attributions

    All content for this solution is sourced from the original question on Stackoverflow.

    The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

    Content TypeOriginal AuthorOriginal Content on Stackoverflow
    QuestionPaulView Question on Stackoverflow
    Solution 1 - AngularjsMichelle TilleyView Answer on Stackoverflow
    Solution 2 - AngularjsStoutieView Answer on Stackoverflow
    Solution 3 - AngularjsJohn SkiterView Answer on Stackoverflow
    Solution 4 - AngularjszbyteView Answer on Stackoverflow
    Solution 5 - AngularjshlissnakeView Answer on Stackoverflow
    Solution 6 - AngularjsJoel TadmorView Answer on Stackoverflow