Improve Angular Performance with React

By Dave Ceddia

Angular + React with ngReact

If you’ve run up against performance problems with Angular due to a high number of watchers or unpredictable and expensive re-renders, ngReact could help.

Or if you have an existing Angular app and you’d just like to try out React without rewriting your whole app, ngReact could help there too.

What Is ngReact?

ngReact is a small wrapper around React (the whole thing is only about 260 lines of code).

With it, you can create an Angular directive which actually renders a React component. ngReact sets up watches on the attributes passed to the directive and re-renders the component when they change.

Where Is It Useful?

If you have large or nested ng-repeats, you’ve probably run into some slowdowns related to the number of watchers on the page.

Likewise if you’ve taken the idea of “make everything a component (directive)” to heart. As an example, a table full of cells with custom directives could add significantly to the number of watchers on the page.

Now, if your app seems fast enough, rewriting parts of it in React is probably not worth the effort. You need to measure first.

How To Measure Watchers

There are 2 tools I know of that are great for measuring the number of watchers on the page.

ng-stats by @kentcdodds displays the watcher count along with a nice little graph of recent digest cycle durations. It’s great for an overview.

ng-stats

Then when you want to dig in, get the bookmarklet from this post by Jason Stitt. It annotates every element on the page with a “data-watchers” attribute, so you can use Inspect Element to figure out how many watchers any given element has created.

#watchers

Even better, you can start at the <body> tag and drill down to the elements that contain the most watchers. The directives with the most watchers are the ones you may want to consider optimizing, or rewriting in React.

Writing React Components

Now that you’ve narrowed down a directive that’s causing problems, you can write a React component to replace it.

Follow the instructions on the ngReact page to install it, then require the ‘react’ module as a dependency:

angular.module('yourApp', ['react'])
    ...

Make sure you include both react and react-dom too, either as script tags in your index.html or with import or require if you’re using them.

Then there are 2 ways to add a React component to Angular: either as a real directive, or by using the react-component directive supplied by ngReact. Their docs cover both ways, but we’ll go over the “real directive” approach here.

Inject the reactDirective service and wrap your React component with it:

var BigList = React.createClass({
  // Defining propTypes is important!
  propTypes: {
    items: React.PropTypes.array
  },
  render: function() {
    return (
      <ul>
        {this.props.items.map(item =>
          <li key={item.id}>{item.name}</li>
        )}
      </ul>
    );
  }
});

app.directive('bigList', function(reactDirective) {
  return reactDirective(BigList);
});

Now you can use bigList like any other Angular directive:

<big-list items="parentCtrl.items"></big-list>

Things to Watch Out For

  1. React components cannot contain Angular elements. If you convert a directive that has a lot of nested directives, you’ll need to convert every directive all the way down the tree.

  2. ngReact looks at the propTypes on the React component to decide which attributes to watch. If you leave off a propType, it will ignore that attribute entirely, and your component probably will render nothing.

If you can’t easily set the propTypes (for instance, if you’re returning a higher-order component), you can pass an array of attributes to watch like this:

app.directive('fancyDragDropThing', function(reactDirective) {
  var wrapped = WrapperComponent(YourComponent);
  return reactDirective(wrapped, ['items']);
});

Wrap Up

This was a quick high-level overview of introducing React into an Angular app to improve performance. Here’s some further reading if you’d like to learn more about React and get started with it:

Translations

This article has been translated into Chinese! You can read it here.