UI components: Angular vs React

Please don't reinvent JavaScript in your web framework

I’ve been building web UIs in Angular and React for the last few years, and I’ve started to greatly prefer React. Extracting and using UI components is just easier and, for lack of a better word, more JavaScripty.

Extracting components in React

Say I notice that I’m creating multiple <span> elements with the same class and icon:

function Main() {
  return (
    <div>
      <span class="alert-tag"><i class="fa alert"></i>foo</span>
      <span class="alert-tag"><i class="fa alert"></i>bar</span>
      <span class="alert-tag"><i class="fa alert"></i>baz</span>
    </div>
  );
}

It’s trivial to refactor this repeated element into its own <Alert> component function within the same file:

function Main() {
  return (
    <div>
      <Alert>foo</Alert>
      <Alert>bar</Alert>
      <Alert>baz</Alert>
    </div>
  );
}

function Alert({ children }) {
  return (<span class="alert-tag"><i class="fa alert"></i>{children}</span>);
}

Super easy, uses JavaScript’s native language constructs, and I was able to do it all within the same file (but I can easily move Alert() elsewhere for wider re-use if needed). It’s just like extracting a function in a “regular” programming language, it’s something you do without even thinking about it.

Extracting Components in Angular

First, we have to create the new component. The most common way to do this in Angular is with Angular CLI and its various ng commands. By default, the command to create a new component (ng generate component Alert) literally touches 5 files:

CREATE src/app/alert/alert.component.css (0 bytes)
CREATE src/app/alert/alert.component.html (23 bytes)
CREATE src/app/alert/alert.component.spec.ts (614 bytes)
CREATE src/app/alert/alert.component.ts (261 bytes)
UPDATE src/app/main.module.ts (720 bytes)

Yikes – that’s definitely overkill for our tiny helper component! Thankfully we can get that down to 2 with the following parameters instead: ng generate component Alert --inlineStyle=true --inlineTemplate=true --skipTests=true

Once we’ve done that, the component file still has an awful lot of boilerplate:

import { Component, OnInit } from '@angular/core';
 
@Component({
  selector: 'alert',
  template: `<span class="alert-tag"><i class="fa alert"></i><ng-content></ng-content></span>`,
  styles: []
})
export class AlertComponent implements OnInit {
  constructor() { }
  ngOnInit() {
  }
}

That can be trimmed down a bit:

import { Component } from '@angular/core';
@Component({
  selector: 'alert',
  template: `<span class="alert-tag"><i class="fa alert"></i><ng-content></ng-content></span>`
})
export class AlertComponent {}

… but we also need to reference the new component in our module file, even if it’s a tiny helper within another component:

import { MainComponent, AlertComponent } from './main.component';
@NgModule({
  declarations: [
    MainComponent,
    AlertComponent
  ],
...

These steps aren’t impossible. They’re negligible for large components, to be honest. Where they become a problem is small components, especially those which are only used within a limited context. The fixed cost of extracting a component is simply much higher in Angular than in React, which limits our ability to write small components in a Clean Code style.

Using Extracted Components

To make matters worse, Angular components often need to be used with Angular-specific syntax instead of standard JavaScript. If you want to generate an <Alert> for every variable in a collection you’d use ngFor instead of a standard JavaScript function like map(). You might also use ngIf, ngSwitch, or Angular’s not-exactly-JavaScript template expressions. It’s not good that Angular is reinventing fundamental language functionality.

Closing thoughts

Working with components in Angular just involves so much ceremony compared to React. I’m always aware that I’m working within the constraints of a framework, whereas React feels like I’m working in regular JavaScript (after the brief introduction to JSX, anyway). I know which I prefer.

headshot

Cities & Code

Top Categories

View all categories