React versus Angular in 2024

Table of Contents

  1. Premise
  2. Step for React
  3. Step for Angular
  4. What is React?
  5. What is Angular?
  6. Developer Experience Comparison
  7. Performance Comparison
  8. Conclusion
  9. Resources

Premise

I set out to build a similarly styled and similarly functional todo/task list application using both React and Angular to compare their setup, developer experience, performance and general usability in 2024.

Both applications are deployed and hosted here:

Angular Task App
React Task App


Setup for React

The React application was scaffolded using bun with Vite and following the wizard steps, choosing React and Typescript

bun create vite react-task-list

✔ Select a framework: › React
✔ Select a variant: › TypeScript
Scaffolding project in /path/to/react-task-list...

The following packages and libraries were added to help with styling and user feedback. Tailwind for styling, Akar icons for UI icons and uuid to handle task list item unique id

"dependencies": {
    "@radix-ui/react-label": "^2.0.2",
    "@radix-ui/react-slot": "^1.0.2",
    "@radix-ui/react-toast": "^1.1.5",
    "akar-icons": "^1.9.31",
    "class-variance-authority": "^0.7.0",
    "clsx": "^2.1.0",
    "lucide-react": "^0.368.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "tailwind-merge": "^2.2.2",
    "tailwindcss-animate": "^1.0.7",
    "uuid": "^9.0.1"
}

Setup for Angular

The Angular application was scaffolded using node with the Angular CLI and following the wizard steps

npx -p @angular/cli ng new angular-task-list

? Which stylesheet format would you like to use? CSS
? Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? No

The following packages and libraries were added to help with styling and user feedback. Tailwind for styling, Akar icons svgs copied for the UI icons and uuid to handle task list item unique id

"dependencies": {
    "@angular/animations": "^17.3.0",
    "@angular/common": "^17.3.0",
    "@angular/compiler": "^17.3.0",
    "@angular/core": "^17.3.0",
    "@angular/forms": "^17.3.0",
    "@angular/platform-browser": "^17.3.0",
    "@angular/platform-browser-dynamic": "^17.3.0",
    "@angular/router": "^17.3.0",
    "ngx-sonner": "^1.0.0",
    "rxjs": "~7.8.0",
    "tslib": "^2.3.0",
    "uuid": "^9.0.1",
    "zone.js": "~0.14.3"
}

What is React?

React is an open-source Javascript library managed by Facebook's React team (React). It has a component-based architecture and declarative views to create interactive and complex UIs. The main advantages of using React include its reusable and predictable code, faster development time, easier debugging and enhanced developer productivity.

React uses a virtual DOM for fast rendering, employs one-way data binding with unidirectional data flow and has a smaller learning curve thus ideal for quick development. It comes with no batteries included and third-party libraries are needed to accomplish more complex logic but due to its popularity there is a huge ecosystem of libraries available.

Below is an example of the TaskCard.tsx component from the task list application to show the colocation of concerns, incorporating the view and logic in the same .tsx file.

TaskCard.tsx

import { Task } from "@/types/task";
import { Button } from "./ui/button";
import { Circle, CircleCheckFill, Cross } from "akar-icons";

const TaskCard = ({
  task,
  onUpdateTask,
  onDeleteTask,
}: {
  task: Task;
  onUpdateTask: (taskId: string) => void;
  onDeleteTask: (taskId: string) => void;
}) => {
  return (
    <div className="flex items-center p-2 justify-between bg-[#121217] rounded-xl my-1">
      <div className="flex items-center">
        <Button
          className="bg-transparent hover:bg-transparent gap-2"
          onClick={() => onUpdateTask(task.id)}
          tabIndex={0}
          aria-label="Check/Uncheck Task"
        >
          {task.completed ? (
            <CircleCheckFill
              className="text-cyan-300 outline-cyan-500"
              strokeWidth={2}
              size={20}
            />
          ) : (
            <Circle
              className="text-cyan-300 outline-cyan-500"
              strokeWidth={2}
              size={20}
            />
          )}
          <span
            className={`${
              task.completed
                ? "text-xs md:text-lg text-gray-100 font-light px-1 line-through opacity-40"
                : "text-xs  md:text-lg text-gray-100 font-light px-1"
            }`}
          >
            {task.item}
          </span>
        </Button>
      </div>
      <div>
        <Button
          className="flex gap-2 bg-transparent text-red-500 h-8 md:h-10 hover:bg-red-800/20"
          variant="destructive"
          onClick={() => onDeleteTask(task.id)}
          aria-label="Delete Task"
          tabIndex={0}
        >
          <Cross strokeWidth={2} size={16} className="md:size-4 size-3" />
        </Button>
      </div>
    </div>
  );
};

export default TaskCard;

React is not very opinionated and allows you to develop the application how you see fit. This can be somewhat of a drawback of React and there are no solid conventions and how things should be done. Other drawbacks include that it's not a complete framework but simply a library and other third-party libraries may be needed for large-scale applications.


What is Angular?

Angular is a full development platform and application-design framework built on Typescript with a similar component-based architecture built and maintained by Google (Angular). It is very much a batteries included framework with integrated libraries, dependency injection and its own Angular CLI.

Angular has a strong emphasis on encapsulation and opinionated application structure. It is an object-orientated framework with an emphasis on classes. It has built-in features like RxJS, the Angular CLI and testing as well as built-in support for HTTP, Ajax and Observables. It utilizes two-way data binding, optimizes coding practices and is focused on mid-level to enterprise scale applications.

Below is an example of the app-task-card components from the task list application to show the separation of concerns, moving the markup and logic to individual files.

task-card.component.html

<div class="flex items-center p-2 justify-between bg-[#121217] rounded-xl my-1">
  <div class="flex items-center justify-center px-4">
    <button
      class="bg-transparent hover:bg-transparent gap-2 inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
      (click)="updateTaskEvent(task().id)"
      tabindex="0"
      aria-label="Check/Uncheck Task"
    >
      @if (!task().completed) {
      <i class="ai-circle text-[#FD33C5] text-xl"></i
      ><span class="text-xs md:text-lg text-gray-100 font-light px-1"
        >{{ task().item }}</span
      >
      } @else {
      <i class="ai-circle-check-fill text-[#FD33C5] text-xl"></i
      ><span
        class="text-xs md:text-lg text-gray-100 font-light px-1"
        [ngClass]="task().completed ? 'line-through opacity-40' : ''"
        >{{ task().item }}</span
      >
      }
    </button>
  </div>
  <div>
    <button
      class="h-8 px-4 flex gap-2 bg-transparent text-red-500 md:h-10 hover:bg-red-800/20 items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
      (click)="deleteTaskEvent(task().id)"
      aria-label="Delete Task"
      tabindex="0"
    >
      <i class="ai-cross text-base"></i>
    </button>
  </div>
</div>

task-card.component.ts

import { CommonModule } from "@angular/common";
import { Component, input, output } from "@angular/core";
import { Task } from "../../../types/task";

@Component({
  selector: "app-task-card",
  templateUrl: "./task-card.component.html",
  styleUrls: ["./task-card.component.css"],
  standalone: true,
  imports: [CommonModule],
})
export class TaskCardComponent {
  public task = input.required<Task>();
  public taskUpdateEvent = output<string>();
  public taskDeleteEvent = output<string>();

  public updateTaskEvent(taskId: string): void {
    this.taskUpdateEvent.emit(taskId);
  }

  public deleteTaskEvent(taskId: string): void {
    this.taskDeleteEvent.emit(taskId);
  }
}

Developer Experience Comparison

React

A huge advantage to React in terms of dev experience is its popularity, meaning there are lots of resources, guides, tutorials and Stack Overflow articles out there. It is also very easy to get started with, anyone with an understanding of HTML and Javascript will feel comfortable using React, although somewhat unconventional in mixing the two in a JSX or TSX file. Another win for React is its flexibility, it isn't opinionated on how developers should treat/write the code.

Angular

A massive selling point for Angular is that it is a "batteries included" framework meaning less of a need for third-party libraries. It is focused on mid-level to enterprise-scale apps. It promotes separation of concerns by isolating the view from the business logic in its component.ts and component.html structure. It is also opinionated on how the code should be structured, this can be an advantage for those used to an OOP style of programming paradigm but from another perspective can be a steeper learning curve for new developers.


Performance Comparison

Both React and Angular projects are deployed to my VPS and built as a single page application with the bundle being hosted via a Docker container and Nginx web server.

Firstly let's take a look at the bundle size between the two projects, the React project /dist folder which was output using tsc && vite build command. And the Angular project /dist folder which was output using ng build.

Output Comparison

Framework/Librarydist folder size
Angular381 KB
React578 KB

We can see that Angular is a smaller output bundle compared to React bundle.

pingdom.com Comparison

Now let's take a look at some metrics when using a website performance benchmark website such as tools.pingdom.com.

Framework/LibraryPeformance GradePage SizeLoad timeNo of Requests
AngularA - 92129.8 KB1.91s10
ReactA - 95136.1 KB1.22s10

Here we find that although Angular is delivering a smaller page size it still loses out to React in both performance grade and load time.

pagespeed.web.dev Comparison

Next let's use pagespeed.web.dev specifically the performance metrics.

Framework/LibraryPeformance GradeFirst Contentful PaintTotal Blocking TimeSpeed IndexLargest Contentful Paint
Angular850.6s30ms0.8s0.7s
React940.7s0ms0.7s0.7s

Again here we see that despite Angular's smaller bundle size it is marginally slower in key performance metrics such as FCP, LCP and overall speed. This must be caveated by the fact that both are small simple todo list applications and a much more complex mid to enterprise-scale application may yield much more varied results.


Conclusion

Whilst React is faster in performance metrics (i.e. on paper) and I personally prefer to develop in React's less opinionated and flexible way of functional programming both are viable options for building simple single-page application in 2024 and it really comes down to personal preference.

If you're a newer developer trying to choose your first library/framework to get into web development then I would lean more towards React, however if your goal is to land a job in large tech company then there's a high likelihood they'll be using Angular and it may be more beneficial to know the key concepts and paradigms of Angular (speaking from personal experience).

But these are only the opinions of one developer and in actual fact there's no wrong choice, the important thing is being confident and understanding the fundamentals of HTML, CSS and Javascript, a framework/library will then be much easier to learn and play around with, but that's the best thing to do, try both options, try to build something interesting and enjoy the process.


Resources

Chris McConnell © 2024