Getting to Grips with React (as an Angular developer)

By Dave Ceddia

From Angular to React

Are you an Angular developer interested in React? Don’t worry, it doesn’t make you a traitor or anything. Really.

Maybe you’ve started to play around already – gone through the official Facebook tutorial, made a few components…

Or maybe you’re where I was a few months ago: no experience with React at all, except you heard it’s fast, and has virtual DOM, and one-way binding, and something something Flux/Redux/Reflux/wtf.

In a series of posts I’m gonna try to help you apply your hard-won knowledge of “Angularisms” to React.

directives == components

In Angular, you’re probably used to writing directives. If you’re following the popular conventions, most parts of your app are represented by a directive or three… and you’re using isolate scopes everywhere. (if that sounds familiar but that’s not you, maybe you’d like to read about converting scope to controllerAs)

React has the same concept: you write components. Break up your app into chunks of functionality, and try to keep the chunks as independent and reusable as possible. In fact, this idea isn’t even specific to React or Angular – it’s just good software development practice. Try to write small, reusable bits of code (functions, components, directives, …whatever you want to call them).

One key difference is that everything is a component in React, from the root node and below. Angular lets you mix and match directives with ng-controller and then routes are special, with their own controllers and templates… React makes this a bit easier. Everything is a component. Pages, buttons, even routes. But we’ll cover those later.

Ok, so React’s “components” are akin to “directives.” What does the code look like?

Here’s an Angular directive that displays the name of a song:

angular.module('demo', []).directive('songName', function() {
  return {
    scope: {
      song: '='
    },
    restrict: 'E',
    template: '<span class="song-name">{{ ctrl.song.name }}</span>',
    controller: function() {},
    controllerAs: 'ctrl',
    bindToController: true
  };
});

Here’s that same component in React:

var SongName = React.createClass({
  propTypes: {
    song: React.PropTypes.object.isRequired
  },
  render: function() {
    return <span className='song-name'>{this.props.song.name}</span>;
  }
});

Right off the bat you can see some similiarities – they both expect to be passed a song object, and both appear to have a template of sorts.

And some differences – the React one has less boilerplate than Angular. Dare I say… cleaner? The expected argument (song) has some kind of type validation. And the HTML has no quotes!

Except the stuff that looks like unquoted HTML isn’t actually HTML. (we’ll get to that in a sec)

React.createClass is similar to angular.directive – it creates a component class. This component must have a render function. The propTypes object is optional, but it’s a good idea to put it in.

Now, to be fair to Angular, v1.5 introduced a component shorthand for directives, so the directive above could be written like this:

angular.module('demo', []).component('songName', {
  bindings: {
    song: '='
  },
  template: '<span class="song-name">{{ $ctrl.song.name }}</span>'
});

Much simpler. It even comes with a default no-op controller! I recommend reading Todd Motto’s article about the component method and trying it out in your own code.

But it still doesn’t have propTypes…

propTypes

Forgotten Props

propTypes is a way to specify the arguments your component expects. You can mark individual props as “required” or “optional” (they’re optional by default). Think of it like type checking.

Here’s the really cool part: if you specify propTypes and say that a prop is required (like above), and you forget to pass it in, you will actually get a warning in the console.

This is awesome, coming from Angular. No more silent failures when you forget to pass an attribute to a directive.

props

What’s a “prop?” It’s short for “property” (thank you, React devs, for not making us type out this.properties or this.propertyTypes…).

You can think of props as attributes passed to your component. Just like in a directive, where you pass attributes on the HTML element – props are passed as attributes on the JSX element.

Using a component

Here’s the usage of that directive in Angular:

// Notice how you have to mentally translate 'songName' to 'song-name'?
<song-name song="ctrl.song"></song-name>

And here’s React:

// Notice how you DON'T need to mentally translate SongName to anything?
<SongName song={theSong}/>

Every tag in JSX can be self-terminated if it has no children.

But let’s talk about JSX for a minute…

HTML inside JS?!

Before I even knew anything about React, I knew it mixed HTML and JS, and I thought that was just ugly. I mean, that’s undoing years of best-practices thinking, right? Since the Dark Days of jQuery we’ve known that directly setting innerHTML on elements from within JS was hackish and performed badly, so why is React making those same mistakes all over again?

So, there are 2 things to realize here:

  1. It’s not a string. Did you notice how there are no quotes around the “HTML”? That’s because it’s not HTML. The lack of quotes is not just syntactic sugar, either. React is not parsing that thing and converting it into HTML.

  2. It’s not HTML. It’s JSX. I know, I know, it looks like HTML. Right now you’re thinking “Pfft JSX… they just changed HTML in subtle ways and gave it a new name.” Well… you could say that. I like to think of it as they gave us a nice syntax sugar over function calls that create DOM elements.

JSX is compiled to Javascript

Function calls that create DOM elements? Yep. See here:

// This JSX...
<span className='song-name'>{this.props.song.name}</span>

// Compiles to this function call:
React.createElement('span', {className: 'song-name'}, this.props.song.name);
// React.createElement('tagName', props, children);

And it kinda makes sense, doesn’t it? HTML creates nested DOM nodes, and we can alternatively represent those nested nodes as nested function calls…

// This is valid JSX:
<div>
  <span className='greeting'>
    <strong>Hello</strong>
    <strong>World</strong>
  </span>
</div>

// ...which compiles to this call:
React.createElement('div', null,
  React.createElement('span', {className: 'greeting'},
      React.createElement('strong', null, 'Hello'),
      React.createElement('strong', null, 'World')
    ));

Technically, these React.createElement calls don’t make real DOM nodes, they create virtual DOM nodes.

But… Separation of Concerns!

Ok so we’re not actually putting HTML strings in Javascript? phew

But the logic is still mixed with the presentation! That can’t be right! It flies in the face of years of software development progress. It’s Just Not Done. You don’t mix view code with logic.

I think this is one of those “cargo cult” things that we all agree on and enforce without truly understanding why. There are some good reasons to separate the view and its logic, but when you step back and look at it there are actually some good reasons to combine them.

You’ve probably written some Angular directives with a controller and a separate template file, yes?

Tell me, how often have you gone in to the template to tweak something without having to look at (or change!) the controller? How often have you changed the controller without having to touch the template?

Do those seem like separated concerns to you?

We like to think that splitting the JS and the HTML into separate files makes them “separated concerns.” Reusability here we come!

Except it rarely works that way. A directive’s controller and template are usually pretty tightly coupled, and naturally so – they’re 2 sides of the same coin. Splitting code into separate files does not automatically lead to separation of concerns.

If you haven’t noticed, I’m trying to make the case that the template and the view logic could actually coexist in the same file and it might actually make more sense to do it that way.

Try it out

I bet you still have doubts. That’s fine. I did too.

Personally, I find it hard to jump on board with things that seem like the complete opposite of what I’ve long believed. I have to try it myself and prove to myself that the new way is not terrible.

I implore you to do the same. Give it five minutes. Go through the official React tutorial (no fancy tooling required – download and run their server, and start typing). Or try out my 3 minute Hello World (no build required!)

You may find, like I did, that writing React components actually feels fun. Or maybe you’ll learn that React is not for you, but at least you will have given it a shot.

I’m going to start mixing in some writing about React with my articles about Angular, specifically with an eye toward helping fellow Angular devs get their footing with React, and map some of our “Angularisms” over to React.

If that sounds good, sign up for my newsletter and I’ll let you know as I publish them!

Learning React can be a struggle — so many libraries and tools!
My advice? Ignore all of them :)
For a step-by-step approach, check out my Pure React workshop.

Pure React plant

Learn to think in React

  • 90+ screencast lessons
  • Full transcripts and closed captions
  • All the code from the lessons
  • Developer interviews
Start learning Pure React now

Dave Ceddia’s Pure React is a work of enormous clarity and depth. Hats off. I'm a React trainer in London and would thoroughly recommend this to all front end devs wanting to upskill or consolidate.

Alan Lavender
Alan Lavender
@lavenderlens