Angular 2 v React with Flux: Dawn of Component Driven UI

I was gonna make a funny blog post comparing Angular 2 and React, satirizing the horrible Batman v Superman movie, but after seeing Captain America 3, I felt bored and disappointed by comic book movies in general and will now acquiesce to writing a standard bland post full of technical jargon.

However I will intersperse funny Homer Simpsons gifs like this to keep us entertained:


Look at it go!

Anyway, seeing how both React and Angular are by far the most popular MV-whatever frameworks in today’s front-end web dev landscape, I’d thought I try a little experiment and do a shoot-out between the two. Having not worked with either since at least the end of last year (with Angular, an even longer time), I figured I’d give myself a little refresher, while also getting a real in-depth critique of their comparable strengths and weaknesses. If you happen to be lazy and have no attention span like most people these days, please scroll to the bottom for a TL;DR summary of my fleeting assessment.

The App

I recreated the iPad version of the iOS Notes app with both libraries/frameworks.

You can view the React version here: React Notes
And the Angular 2 one here: Angular Notes

Also please check out the actual code on Github: Repo

OK, this was a very boring choice to recreate, but I’ve been using that app a lot lately. It’s also trivial enough where I don’t have to implement too much logic but also just enough to give me a taste of what it would feel like to actually use it for something more substantial.

The app, if you are unfamiliar, is simple. There’s an editable text area in the middle. Click on it and write something. It saves. Click on the pencil icon in the corner to make a new one, the trash icon to delete the current one. Click on the Notes button in the top left to open a sidebar to show a list of all your notes. Click on a note to see and edit it.


Not much to it.

React with Flux

I started out writing the app first with React, since I actually have experience using it. I’d never used it with Flux architecture however, so I went and took a look at the official React tutorial with Flux. I lifted some of the boilerplate code from the tutorial into the project (namely the dispatcher implementation, which is just a very basic Observer object with promises).

If you aren’t familiar with it, Flux is an architecture pattern promoting an uni-directional flow of data. I’m not going to give any more than a cursory summary of Flux, because you can look it up yourself, but basically, Flux can be broken down into four discrete parts: actions, dispatchers, stores, and views.

Actions are concrete directives an application can take. Actions flow into a dispatcher, which act as a centralized event bus. The dispatcher then notifies stores (which have previously registered callbacks to the dispatcher). Stores, which handle application state and hold data, then emit change events which are listened to by the views (which are React components in this scenario). The views then of course update and re-render what’s shown to the user. Any further actions are triggered by the view, and the uni-directional flow of data is restarted.

var _callbacks = [];

export default class Dispatcher {

 
  register(cb) {
    _callbacks.push(cb);
    return _callbacks.length - 1;
  }

  dispatch(payload) {
    _callbacks.forEach((cb)=> {
      cb(payload);
    });
  }
}

The dispatcher class from Facebook is a primitive observer, that simply registers callbacks and invokes all of them at once in a single dispatch (no custom events). I removed their promise implementation as there were no asynchronous data calls in my app.

  constructor() {
    super();

    AppDispatcher.register((payload)=> {
      var { val, id, actionType } = payload.action;

      switch(actionType) {
        case NoteConstants.CREATE:
          Notes.create(val);
          this.emit(CHANGE_EVENT);
          break;

        case NoteConstants.UPDATE:
          Notes.update(id, val);
          Notes.currId = id;
          this.emit(CHANGE_EVENT);
          break;

        case NoteConstants.DESTROY:
          Notes.destroy(id);
          let notes = this.getNotes();

          if (notes.length) {
            Notes.currId = notes[0].id;
          } else {
            Notes.currId = null;
          }

          this.emit(CHANGE_EVENT);
          break;

       // more switch cases
      }
    });
  }

A store registers a callback to be triggered by the dispatcher. When invoked, it uses a switch case to process the appropriate action. The store then emits an event (subclassing Node’s Event Emitter) which is listened to by a view.

All in all I found Flux to be a very sound paradigm. I don’t think it’s the end and be all of ways to build your app, but it’s certainly a well designed and structured one. Like most JavaScript design patterns, it relies heavily around the pub-sub/observer pattern, which is definitely my preferred method of communicating between distinct objects. The uni-directional data flow and actions are also enticing to me because you are breaking down and structuring the app into very concise and linear segments, making it very obvious as to what’s happening on a high level.

However, as nice as I found the precision and structure of Flux to be, it was ultimately overkill for an app of this size. Since this app doesn’t have many actions/events, you don’t really to need to have concrete action directives or a centralized dispatcher for event notification. Initially I was not going to use Flux and simply use a singular instance of the Node.js Event Emitter, which would have been sufficient for what I needed to accomplish. If I had decided to have gone that route, I would have avoided writing a lot of boilerplate plate code, but it would probably not be sufficient if the app grew in size.

An alternative pattern to Flux is Reflux, which is a somewhat parsed down version of it, removing the singleton dispatcher and instead moving that responsibility to the action itself.

What I wanted to emphasize is that Flux is definitely not a framework, simply an architecture pattern, and it’s up to you to implement it yourself. If you want an out of a box solution for your project, Facebook has made their implementation available.

As for React.js itself, I feel mostly warm and fuzzy about it. The main issue I have with it is I’d very much rather have automatic two-way bindings, and prefer Angular much more in that regard. I know two-way binding is an anti-pattern in regards to Flux, but I really hate, for example, having to always include a handler function on an HTML input’s change event simply to just manually sync data on the model/state.

Also, I’m not too big of a fan of JSX and don’t care for mixing my HTML templates with JS (and I know you can have independent JSX files, but it’s much more annoying) as it conflicts with the separations of concerns programming principle that was beaten into my head so many years ago, but I’m coming to terms with it. Also, seeing how web components promote sticking the Javascript, HTML, AND CSS all together, it just seems like things are trending inevitably in that direction.

What’s cool about React ultimately, is that unlike Angular or Ember, it’s really just a view controller (and a really fast one because it’s use of virtual DOM). You could for example use it with Backbone, taking away the shitty manual Backbone View and replacing it with React, all the while still using Backbone models, collections, and the router. React is really flexible and un-opinionated in that regard. I mean in the React tutorial they freaking use jQuery for Ajax!


Stay with me

Angular 2

Although the majority of the app logic was already written (with the majority existing in the store), converting it to Angular 2 was somewhat challenging because of my lack of familiarity. Even though I have a fair amount of experience with Angular 1, 2 is completely different.

Gone are controllers–everything is now component driven. Templating syntax is also different, with event bindings and familiar ‘ng’ directives getting an overhaul.

Compounded with severely lacking documentation (which is expected for a beta version), with the only significant amount of anything geared exclusively for TypeScript, it took a little bit of time to figure out. It’s actually fairly apparent that Angular 2 was created with TypeScript in mind, notably making use of Typescript’s decorators for everything. In fact, the docs come only in three versions: TypeScript, plain ES5 (OK?), and Google Dart (LOL).

Despite all the changes, if you are already familiar with component driven UI development, it should be pretty straight forward. Also, if you already know Angular 1, all the familiar ingredients still remain: directives, services, providers, dependency injection, etc.

  @Component({
    selector: 'my-app',
    template: `
      <div (click)="closeSidebar($event)">
        <notes-header></notes-header>
        <notes-sidebar></notes-sidebar>
        <notes-note></notes-note>
      </div>
    `,
    directives: [Header, Note, Sidebar],
    providers: [NotesService]
  })
  export default class AppComponent {
  // .etc

Example of the decorator for the app level component. Decorators appear above ES6 style classes as metadata to dictate class functionality.

Somehow I was able to mostly keep everything in plain ole’ ES6 JS (keeping the .js file extension) with the help of several Babel plugins that allowed the usage for the decorator syntax and a couple other TypeScript style things. Notably, injecting a service/provider into a component won’t work unless using TypeScript’s function parameter typing.

One of the big changes in Angular 2 is that there’s no more $scope. You simply add properties to the class instance, and they magically are processed by the templating engine. I’m actually not sure if they completely revamped the internals of the framework, and whether or not it still relies on the digest cycle along with dirty checking for re-rendering.



 <ul class="sidebar" [class.show]="isOpen">
    <li *ngFor="let note of notes" [class.selected]="note.isSelected" (click)="selectNote(note)">
      <span class="note-name">{{note.name}}</span>
      <span class="note-date">{{note.date | sidebarDatePipe}}</span>
    </li>
 </ul>


Example of new templating syntax. Note the changes to ng-class, and ng-repeat.

Architecturally, Angular 2 seems rather the same than it’s predecessor. Instead of nested controllers passing around data, you have nested components passing around data. Gone are modules, instead you create your own modularity using the ES6 native module system. In fact you could simply bypass the injector completely for services, though the Angular team doesn’t recommend it.

Communication between disparate components are accomplished in a variety of ways, either passing parameters through parent/child components similarly to React, or relying on a event system or shared service. For my app, I simply chose to go with the shared service route, with the store for the React version basically being transformed to a service. Angular 2 also includes their own version of an event emitter, and I utilized it in pretty much the same way I did for the React store.

There’s plenty of other new features that I haven’t tried with this demo, such as inputs/outputs on components. Additionally, the Angular router, http, animations, forms, and others remain to complete the full-fledged framework.


Almost done!

Verdict

React and Angular 2 are both good options for starting a new project utilizing component driven UI development. Neither is better than the other, and it’s simply up to you whether to decide what you prefer or feel more comfortable with.

Personally, I would give React the edge, simply because Angular 2 is still in beta mode, and it’s questionable whether or not it’s production ready. React also allows for more flexibility, allowing the developer more freedom to cherry-pick whatever libraries/packages they feel most suitable for their needs, which ultimately I feel is more aligned with the temperament of JS-based development.


So much to choose from!

React Pros

  • library and not a framework, only a view layer and more agnostic because of this
  • fast rendering via virtual DOM
  • established, larger community usage, and trending upwards
  • Flux is a proven architecture pattern with a lot of supporters

React Cons

  • flexibility might be problematic for someone who’s less experienced
  • if using Flux, user has to implement it themselves
  • JSX could be unattractive for some developers

Angular 2 Pros

  • monolithic framework, provides everything you need to build an app
  • two-way binding
  • plenty of HTML directives which would have to be otherwise manually coded in React

Angular 2 Cons

  • still in beta mode, poor documentation
  • monolithic framework, less flexibility
  • ostensibly forced to use TypeScript
  • very different from Angular 1, might be a steep learning curve for some


Goodbye!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s