Why React?

Fernando
Fernando

The project team wants to move away from AngularJS (v1) for all new modules. What do we choose instead?

Angular 2+ (now at version 6) is the obvious first option.

This article is an attempt to explain why I prefer React instead.

Busy readers may want to jump straight to the summary at the end.

React Principles

React is based on solid design principles, most of which I value.

Here I summarize the ones I find most relevant in our evaluation and comparison with Angular.

Composition

It's easy to reuse components in Angular. However, it's hard to compose them.

This proved to be a weakness of Angular in our experience. I think this is mainly due to components not being first-class, templates not being data, pervasive mutability (2-way bindings), and broad features you are forced to buy into (DI, custom namespaces).

Two concrete examples from our last Angular project:

  • We built a non-trivial solution to deal with field-level permissions declaratively. We run into more than a few problems mostly fighting against Angular internals, other directives, race conditions, performace, and breakages after version changes. I haven't yet proved it, but I'm pretty confident it can be done in React with just function compositions.
  • Lack of "higher order components". That is: passing components as arguments and making components/directives modify other components. Angular's transclude feature is a limited and complex kludge compared to, again, simple function composition.

In contrast, React components are simple to compose: they are "first-class" and can be passed around (aka Higher-Order Components).

Here are some public extreme examples of what's possible on React thanks its more composable nature:

Beyond the DOM

Most of React is independent of HTML and web browsers.

The core of React's implementation works for other targets. Some examples:

React's architecture and concepts having been proven and applied successfully even outside of the JS world, like ComponentKit for iOS.

Stability and Dogfooding

The React team has been very cautious about breaking compatibility. In those few cases they did, they did so incrementally, with warnings in the library and tools to automate migration.

Did you know React 16 is a complete rewrite if its internals (codename: React Fiber) ? Fully backwards compatible.

More stable means less risk. It's also more mature and has more years of refinement than Angular 2+.

Also: React is being used for many different public-facing applications: Facebook and Instagram (where React originated), Twitter, Airbnb, Netflix, Dropbox, WhatsApp.

Developer Experience / Debugging / Optimized for Tooling

Given its functional approach (that is, components being conceptually just functions of props and state), it's quite easy to debug components.

React DevTools gives you an easy way to inspect the state of components in Chrome.

When using good state-management in your application (like Redux) you can achieve "live coding" which allows you to change the code of the app on the fly, while the app is running, without the need to reload the page. This is a big productivity boost.

Live coding is probably better achieved with ClojureScript (see figwheel), since the language is better suited than JavaScript for functional programming.

Common Abstraction

React: "In general we resist adding features". Angular, on the other hand, comes with a truckload of features which might not be the best fit for your solution.

Interoperability

Thanks to the other principles, it's easy to integrate React with non-react libs and components.

For example, it's easy to include a React component within an Angular app. We might follow this approach at our current project.

Also, it's simpler to have multiple React apps coexist. Example, using Redux: https://redux.js.org/recipes/isolating-subapps.

Escape Hatches

React is based on Functional principles and meant to build UIs in a declarative way.

To be honest, tasks which are inherently about mutable state (like hanlding Forms, focus, or text selections) become harder under this approach.

React gives you options (like refs) for these special cases and there are already elegant common patterns to deal with them.

Some points I do not like about Angular

  • Angular Re-invents concepts and implements many things which already exist in JavaScript. More than half of the documentation and tutorials on Angular are dedicated to these re-invented wheels, which are not needed when using React. Examples:

    • NG Modules and its Dependency Injection
    • Custom Template language (vs. plain JavaScript)
      • Reinvents conditionals (IFs), Repeats (for), Switches, variable "scopes", evaluation context.
      • "Pipes"
      • Custom "expression language", with its own evaluation rules
      • Additional non-HTML-compatible syntax
    • "Transclusion": a complex workaround to "pass" components as arguments to other components. This is trivial and much more flexible in React: you simply pass a function as parameter.
  • Non-functional, two-way binding approach

    • More familiar (easier), but results in more complexity
    • Makes it harder to compose and reuse
    • Harder to unit test
    • ... to debug
    • ... to achieve live coding. That is, changing the JS code live, without reloading the browser page
  • Bigger. More complex. More lock-in.

What about WebComponents? Doesn't it make React obsolete?

Web Components is an interesting standard. I have no experience using it yet. However, it looks like it doesn't replace what React+Redux brings to the table: state management and keeping your DOM in sync with it.

While you might want to use web components for some pieces of UI, you'd still need to glue them together and manage the state of the application. And if a web component is complex enough, you might want to use React to implement it.

So, the way I see it, it makes a lot of sense to use React (or a similar library) both "around" web components, and inside of them.

TL;DR summary for busy readers {#summary}

Pros of React:

  • Grounded on solid principles
  • Functional approach (vs two-way binding and shared state)
  • Leverages JavaScript instead of poorly re-inventing the wheel
    • less concepts to learn
    • less concepts to fight against, less constraints
    • less specialized tooling required
    • simpler to unit test
    • plays better with other libs
  • Smaller. React's public API for users is roughly 10 functions
  • More stable, longer-term compatibility, more mature, less risk
  • Bigger ecosystem (not just due to "popularity". I think it's also because its architecture allows for more leverage and composability)
  • More innovation happening around it: functional, GraphQL, immutable collections, explicit state-management, ClojureScript, ReasonML, hot reloading, react native, server-side rendering, static site generation
  • Better development tools
  • More "composable" components
  • Developers can leverage React's knowledge for other rendering targets
  • Natural hot code reloading (see Dan Abramov's talk from 2015!)
  • Simpler unit-testing
  • More modular: pick your libs for each problem
  • For me at least: it's easier to understand and predict what React does vs Angular. Less "WTF" moments

Pros of Angular:

  • It is more familiar to most developers. React's functional and more "pure" approach (especially when using Redux) requires a different way of thinking
  • Some things are easier to do in Angular (say, mutating any DOM element at any time). React requires more thinking for these kind of things, and sometimes more code
  • In AngularJS, more decisions have been made for you

Conclusion

I have no bias to pick one or the other. There's no hidden agenda. My only interest is on building better and more maintainable solutions.

I think there are enough long-term advantages to pick React for our project. I also believe it benefits the team and our customer, giving developers experience with technologies we can leverage for other rendering targets.

Sidenote: In my experience using React from ClojureScript (with reagent and re-frame), ClojureScript is a better fit for React than JavaScript. React's functional principles are more natural in ClojureScript, and Clojure's syntax makes it all simpler (no need for extensions like JSX). Actually, if you come from JavaScript ES5, the cognitive load of learning all of the new ES6 syntax is probably higher than learning ClojureScript!. That said, I understand that pushing for Clojure would be a hard sell... big companies want to "play it safe" and use the most popular languages, so we will surely stay in JS land.


To stay on top of React news, I follow Dan Abramov and Andrew Clark on Twitter.