JavaScript
Article

React for Angular Developers

By Mark Brown

This article was peer reviewed by Craig Bilner. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!

This article is for developers who are familiar with Angular 1.x and would like to learn more about React. We’ll look at the different approaches they take to building rich web applications, the overlapping functionality and the gaps that React doesn’t attempt to fill.

After reading you’ll have an understanding of the problems that React sets out to solve and how you can use the knowledge you have already to get started using React in your own projects.

Frameworks vs Libraries

Angular is a framework, whereas React is a library focused only on the view layer. There are costs and benefits associated with both using frameworks and a collection of loosely coupled libraries.

Frameworks try to offer a complete solution and they may help organize code through patterns and conventions if you’re part of a large team. However, having a large API adds cognitive load when you’re writing and you will spend a lot more time reading documentation and remembering patterns — especially in the early days when you’re still learning.

Using a collection of loosely coupled libraries with small APIs is easier to learn and master, but it means that when you run into problems you’ll need to solve them with more code or pull in external libraries as required. This usually results in you having to write your own framework to reduce boilerplate.

Out Of The Box

Angular gives you a rich feature set for building web applications, among it’s features are:

  • HTML templates with dynamic expressions in double curlies {{ }}
  • Built-in directives like ng-model, ng-repeat and ng-class for extending the capability of HTML
  • Controllers for grouping logic and passing data to the view
  • Two-way binding as a simple way to keep your view and controller in sync
  • A large collection of modules like $http for communicating with the server and ngRoute for routing
  • Custom directives for creating your own HTML syntax
  • Dependency injection for limiting exposure of objects to specific parts of the application
  • Services for shared business logic
  • Filters for view formatting helpers

React on the other hand gives you:

  • JSX syntax for templates with JavaScript expressions in single curlies { }
  • Components, which are most like Angular’s element directives

React is unopinionated when it comes to the rest of your application structure and it encourages the use of standard JavaScript APIs over framework abstractions. Rather than providing a wrapper like $http for server communication you can use fetch() instead. You’re free to use constructs like services and filters but React won’t provide an abstraction for them. You can put them in JavaScript modules and require them as needed in your components.

So, while Angular gives you a lot more abstractions for common tasks React deliberately avoids this to keep you writing standard JavaScript more often and to use external dependencies for everything else.

Bootstrapping

Initializing Angular apps requires a module, a list of dependencies and a root element.

let app = angular.module('app', [])
let root = document.querySelector('#root');
angular.element(root).ready(function() {
  angular.bootstrap(root, ['app']);
});

The entry point for React is rendering a component into a root node, It’s possible to have multiple root components too.

let root = document.querySelector('#root');
ReactDOM.render(<App />, root)

Templates

The anatomy of an Angular view is complex and has many responsibilities, your HTML templates contain a mix of directives and expressions which tie the view and the associated controllers together. Data flows throughout multiple contexts via $scope.

In React it’s components all the way down, data flows in one direction from the top of the component tree down to the leaf nodes. JSX is the most common syntax for writing components which transforms a familiar XML structure into JavaScript. Whilst this does resemble a template syntax it compiles into nested function calls.

const App = React.createClass({
  render: function() {
    return (
      <Component>
        <div>{ 2 + 1 }</div>
        <Component prop="value" />
        <Component time={ new Date().getTime() }>
          <Component />
        </Component>
      </Component>
    )
  }
})

The compiled code below should help clarify how the JSX expressions above map to createElement(component, props, children) function calls.

var App = React.createClass({
  render: function render() {
    return React.createElement(
      Component,
      null,
      React.createElement("div", null, 2 + 1),
      React.createElement(Component, { prop: "value" }),
      React.createElement(
        Component,
        { time: new Date().getTime() },
        React.createElement(Component, null)
      )
    );
  }
});

Template Directives

Let’s look at how some of Angular’s most used template directives would be written in React components. Now, React doesn’t have templates so these examples are JSX code that would sit inside a component’s render function. e.g.

class MyComponent extends React.Component {
  render() {
    return (
      // JSX lives here
    )
  }
}

ng-repeat

<ul>
  <li ng-repeat="word in words">{ word }</li>
</ul>

We can use standard JavaScript looping mechanisms such as map to get an array of elements in JSX.

<ul>
  { words.map((word)=> <li>{ word }</li> )}
</ul>

ng-class

<form ng-class="{ active: active, error: error }">
</form>

In React we’re left to our own devices to create our space separated list of classes for the className property. It’s common to use an existing function such as Jed Watson’s classNames for this purpose.

<form className={ classNames({active: active, error: error}) }>
</form>

The way to think about these attributes in JSX is as if you’re setting properties on those nodes directly. That’s why it’s className rather than the class attribute name.

formNode.className = "active error";

ng-if

<div>
  <p ng-if="enabled">Yep</p>
</div>

if-else statements don’t work inside JSX because JSX is just syntactic sugar for function calls and object construction. It’s typical to use ternary operators for this or to move conditional logic to the top of the render method, outside of the JSX.

// ternary
<div>
  { enabled ? <p>Enabled</p> : null }
</div>

// if/else outside of JSX
let node = null;
if (enabled) {
  node = <p>Enabled</p>;
}
<div>{ node }</div>

ng-show / ng-hide

<p ng-show="alive">Living</p>
<p ng-hide="alive">Ghost</p>

In React you can set style properties directly or add a utility class such as .hidden { display: none } to your CSS for the purpose of hiding your elements (which is how Angular handles it).

<p style={ display: alive ? 'block' : 'none' }>Living</p>
<p style={ display: alive ? 'none' : 'block' }>Ghost</p>

<p className={ classNames({ hidden: !alive }) }>Living</p>
<p className={ classNames({ hidden: alive }) }>Ghost</p>

You’ve got the hang of it now. Instead of a special template syntax and attributes you’ll need to use JavaScript to achieve what you want instead.

An Example Component

React’s Components are most like Angular’s Directives, they are used primarily to abstract complex DOM structures and behavior into reusable pieces. Below is an example of a slide show component which accepts an array of slides, renders a list of images with navigational elements and keeps track of it’s own activeIndex state to highlight the active slide.

<div ng-controller="SlideShowController">
  <slide-show slides="slides"></slide-show>
</div>
app.controller("SlideShowController", function($scope) {
  $scope.slides = [{
    imageUrl: "allan-beaver.jpg",
    caption: "Allan Allan Al Al Allan"
  }, {
    imageUrl: "steve-beaver.jpg",
    caption: "Steve Steve Steve"
  }];
});

app.directive("slideShow", function() {
  return {
    restrict: 'E',
    scope: {
      slides: '='
    },
    template: `
      <div class="slideshow">
        <ul class="slideshow-slides">
        <li ng-repeat="slide in slides" ng-class="{ active: $index == activeIndex }">
          <figure>
            <img ng-src="{{ slide.imageUrl }}" />
            <figcaption ng-show="slide.caption">{{ slide.caption }}</figcaption>
          </figure>
        </li>
        </ul>
        <ul class="slideshow-dots">
          <li ng-repeat="slide in slides" ng-class="{ active: $index == activeIndex }">
            <a ng-click="jumpToSlide($index)">{{ $index + 1 }}</a>
          </li>
        </ul>
      </div>
    `,
    link: function($scope, element, attrs) {
      $scope.activeIndex = 0;

      $scope.jumpToSlide = function(index) {
        $scope.activeIndex = index;
      };
    }
  };
});

The Slideshow Component in Angular

See the Pen Angular Slideshow by SitePoint (@SitePoint) on CodePen.

This component in React would be rendered inside another component and passed the slides data via props.

let _slides = [{
  imageUrl: "allan-beaver.jpg",
  caption: "Allan Allan Al Al Allan"
}, {
  imageUrl: "steve-beaver.jpg",
  caption: "Steve Steve Steve"
}];

class App extends React.Component {
  render() {
    return <SlideShow slides={ _slides } />
  }
}

React components have a local scope in this.state which you can modify by calling this.setState({ key: value }). Any changes to state causes the component to re-render itself.

class SlideShow extends React.Component {
  constructor() {
    super()
    this.state = { activeIndex: 0 };
  }
  jumpToSlide(index) {
    this.setState({ activeIndex: index });
  }
  render() {
    return (
      <div className="slideshow">
        <ul className="slideshow-slides">
          {
            this.props.slides.map((slide, index) => (
              <li className={ classNames({ active: index == this.state.activeIndex }) }>
                <figure>
                  <img src={ slide.imageUrl } />
                  { slide.caption ? <figcaption>{ slide.caption }</figcaption> : null }
                </figure>
              </li>
            ))
          }
        </ul>
        <ul className="slideshow-dots">
          {
            this.props.slides.map((slide, index) => (
              <li className={ (index == this.state.activeIndex) ? 'active': '' }>
                <a onClick={ (event)=> this.jumpToSlide(index) }>{ index + 1 }</a>
              </li>
            ))
          }
        </ul>
      </div>
    );
  }
}

Events in React look like old-school inline event handlers such as onClick. Don’t feel bad though, under the hood it does the right thing and creates highly performant delegated event listeners.

The Slideshow Component in React

See the Pen React SlideShow by SitePoint (@SitePoint) on CodePen.

Two-Way Binding

Angular’s trusty ng-model and $scope form a link where the data flows back and forth between a form element and properties on a JavaScript object in a controller.

app.controller("TwoWayController", function($scope) {
  $scope.person = {
    name: 'Bruce'
  };
});
<div ng-controller="TwoWayController">
  <input ng-model="person.name" />
  <p>Hello {{ person.name }}!</p>
</div>

React eschews this pattern in favor of a one-way data flow instead. The same types of views can be built with both patterns though.

class OneWayComponent extends React.Component {
  constructor() {
    super()
    this.state = { name: 'Bruce' }
  }
  change(event) {
    this.setState({ name: event.target.value });
  }
  render() {
    return (
      <div>
        <input value={ this.state.name } onChange={ (event)=> this.change(event) } />
        <p>Hello { this.state.name }!</p>
      </div>
    );
  }
}

The <input> here is called a “controlled input”, this means its value is only ever changed when the render function is called (on every key stroke in the example above). The component itself is called “stateful” because it manages its own data. This isn’t recommended for the majority of components, the ideal is to keep components “stateless” and have data passed to them via props instead.

See the Pen One-Way Data Flow in React by SitePoint (@SitePoint) on CodePen.

Typically, a stateful Container Component or Controller View sits at the top of the tree with many stateless child components underneath, for more information on this read What Components Should Have State? from the docs.

Call Your Parents

Whilst data flows down in one direction it’s possible to call methods on the parent through callbacks, this is usually done in response to some user input. This flexibility gives you a lot of control when refactoring components to their simplest presentational forms. If the refactored components have no state at all they can be written as pure functions.

// A presentational component written as a pure function
const OneWayComponent = (props)=> (
  <div>
    <input value={ props.name } onChange={ (event)=> props.onChange(event.target.value) } />
    <p>Hello { props.name }!</p>
  </div>
);

class ParentComponent extends React.Component {
  constructor() {
    super()
    this.state = { name: 'Bruce' };
  }
  change(value) {
    this.setState({name: value});
  }
  render() {
    return (
      <div>
        <OneWayComponent name={ this.state.name } onChange={ this.change.bind(this) } />
        <p>Hello { this.state.name }!</p>
      </div>
    )
  }
}

This might seem like a round-about pattern at first if you’re familiar with two-way data binding. The benefit of having a lot of small presentational “dumb” components that just accept data as props and render them is that they are simpler by default, and simple components have far fewer bugs. This also prevents the UI from being in an inconsistent state which often occurs if data is in multiple places and needs to be maintained separately.

Dependency Injection, Services, Filters

JavaScript Modules are a much better way to handle dependencies, you can use them today with a tool like Webpack, SystemJS or Browserify.

// An Angular directive with dependencies
app.directive('myComponent', ['Notifier', '$filter', function(Notifier, $filter) {
  const formatName = $filter('formatName');

  // use Notifier / formatName

}]

// ES6 Modules used by a React component
import Notifier from "services/notifier";
import { formatName } from "filters";

class MyComponent extends React.Component {

  // use Notifier / formatName

}

Sounds Great, Can I Use Both!?

Yes! It’s possible to render React components inside of an existing Angular application, Ben Nadel has put together a good post with screencast on how to render React components inside of an Angular directive. There’s also ngReact which provides a react-component directive for acting as the glue between React and Angular.

If you’ve run into rendering performance problems in certain parts of your Angular application, it’s possible you’ll get a performance boost by delegating some of that rendering to React. That being said, it’s not ideal to include two large JavaScript libraries which solve a lot of the same problems, even though React is just the view layer it’s roughly the same size as Angular so that weight may be prohibitive based on your use case.

While React and Angular solve some of the same problems they go about it in very different ways. React favors a functional declarative approach where components are pure functions free of side effects. This functional style of programming leads to fewer bugs and is simpler to reason about.

How About Angular 2?

Components in Angular 2 resemble React components in a lot of ways. The example components in the docs have a class and template in close proximity, events look similar, it explains how to build views using a Component Hierarchy just as you would if you were building it in React and it embraces ES6 modules for dependency injection.

// Angular 2
@Component({
  selector: 'hello-component',
  template: `
    <h4>Give me some keys!</h4>
    <input (keyup)="onKeyUp($event)" />
    <div>{{ values }}</div>
  `
})
class HelloComponent {
  values='';
  onKeyUp(event) {
    this.values += event.target.value + ' | ';
  }
}

// React
class HelloComponent extends React.Component {
  constructor(props) {
    super()
    this.state = { values: '' };
  }
  onKeyUp(event) {
    const values = `${this.state.values + event.target.value} | `;
    this.setState({ values: values });
  }
  render() {
    return (
      <div>
        <h4>Give me some keys!</h4>
        <div><input onKeyUp={ this.onKeyUp.bind(this) } /></div>
        <div>{ this.state.values }</div>
      </div>
    );
  }
}

A lot of the work on Angular 2 has been making it perform DOM updates a lot more efficiently. The previous template syntax and complexities around scopes led to a lot of performance problems in large apps.

A Complete Application

In this article I’ve focused on templates, directives and forms but if you’re building a complete application you’re going to require other things to help you manage your data model, server communication and routing at a minimum. When I first learnt Angular and React I created an example Gmail application to understand how they worked and to see what the developer experience was like before I started using them in real applications.

You might find it interesting to look through these example apps to compare the differences in React and Angular, the React example is written in CoffeeScript with CJSX which I still like, even now in December of 2015! The React community is gathering around ES6 with Babel and Webpack though, so that’s the tooling I would suggest adopting if you’re starting today.

There’s also the TodoMVC applications you could look at to compare:

Learning Resources

Learning React has been enjoyable, it’s taught me more about functional programming and has a vibrant community around it contributing their own interesting pieces to the React ecosystem. Andrew Ray has written a few great introductory posts on React and Flux, the official React tutorial is the go-to place to get started. Enjoy!

Free Guide:

7 Habits of Successful CTOs

"What makes a great CTO?" Engineering skills? Business savvy? An innate tendency to channel a mythical creature (ahem, unicorn)? All of the above? Discover the top traits of the most successful CTOs in this free guide.

  • http://bello.li/ Lucas S. B. Mastella

    Distinguish the differences between tools that have distinct purposes
    should not be used as arguments reference to support points of view. If
    AngularJS developers aim to learn another tool like React, you don’t
    have to convince them to use it, they are already here for that.

    Now, a few points for the padawans readers:

    Regardless if it’s a framework or library or the size of the team, you
    always have to organize code through patterns and conventions.
    – Frameworks don’t keep you from writing standard JavaScript. You do because you want or don’t know how to use.
    – You’re free to use built-in wrappers. Just because a resource is available, doesn’t mean you have to use it.

    BTW, thanks for the learning resources references about React.

    • Lars Jeppesen

      And once they learn React, it’s easy to switch back to Angular2 :)

      • markbrown4

        Indeed :) I find it interesting how these big frameworks and standards like web components are influencing each another.

        • Lars Jeppesen

          Yes, it’s a great time to be a frontend developer..

  • elijen

    This article should be called “Why JSX sucks?”

  • Richard Chu

    Based on the previous article written by this guy, this one should be avoided. I cant believe Sitepoint continues to feature this guy.

    THis guy is also one of my main reason to not commit to sitepoint, clearly so biased towards react for a tech resource site.

    Perhaps someone should write an article about Angularjs 2 for react developers.

Recommended
Sponsors
Because We Like You
Free Ebooks!

Grab SitePoint's top 10 web dev and design ebooks, completely free!

Get the latest in JavaScript, once a week, for free.