Why I Switched to React (and Why I Almost Didn't)

By Odilon8 min read

Why I Switched to React (and Why I Almost Didn't)#

It was late at night and we were trying to debug an Angular 1.x directive that had three nested isolate scopes and two-way bindings going in directions I could not follow anymore. A colleague leaned back in his chair and said something like, "You know, in React this whole thing would be one function."

I told him he sounded like a fanboy.

He was right, though.

Staring at a directive that nobody on the team fully understood, I started to wonder if there was something fundamentally different about how React approached the same problem.

The Thing That Clicked#

Over the next couple of weeks, I worked through links and resources: Dan Abramov's blog posts, the React docs (which were actually good, even back then), conference talks. I was skeptical, because I had already invested years in Angular and I did not want to start over. In my experience so far, switching frameworks was mostly a lateral move — different syntax, same problems.

But the component model was different in a way I did not expect.

A React component is a function. It takes data, it returns a description of what should be on screen. That is the whole contract. There is no hidden lifecycle complexity lurking in base classes you did not write. There are no watchers firing in some order you have to memorize.

jsx
// A product card that fetches nothing, manages nothing — it just renders
function ProductCard({ product, onAddToCart }) {
  return (
    <div className="product-card">
      <img src={product.imageUrl} alt={product.name} />
      <h2>{product.name}</h2>
      <p className="price">${product.price.toFixed(2)}</p>
      <button onClick={() => onAddToCart(product.id)}>
        Add to Cart
      </button>
    </div>
  );
}

You know exactly what this component needs. You know what events it emits. When it breaks, you know where to look. Coming from environments where a function could have implicit side effects on global state you never even knew existed, this felt liberating.

Compare that to the Angular 1 directive we were debugging. Isolate scope, two-way binding, a link function that mutated the DOM directly. There were genuinely smart people on my team who never fully understood how those interacted.

JSX: I Hated It at First#

My first reaction to JSX was visceral. HTML inside JavaScript? This goes against everything I learned about separation of concerns.

I think I held that opinion for about two weeks. Then I was tracking down a bug where a button was showing up when it should not have been, and I realized I was reading one file instead of jumping between a template and a controller. The structure of the UI and the logic that drives it were right there together.

jsx
// This is the markup AND the logic. They belong together.
function UserActions({ user, currentUserId }) {
  const isOwner = user.id === currentUserId;
  const canEdit = isOwner || user.role === 'admin';

  return (
    <div className="actions">
      {canEdit && <button onClick={() => openEditModal(user)}>Edit</button>}
      {isOwner && (
        <button className="danger" onClick={() => confirmDelete(user.id)}>
          Delete Account
        </button>
      )}
    </div>
  );
}

Angular's structural directives (*ngIf, *ngFor) do the same thing, but the mental context switching between a TypeScript class and an HTML template is friction I do not miss. This is sometimes called "the colocation argument" — it can sound pretentious, but it is correct.

Being Honest About the Other Frameworks#

I do not want to pretend React is the obvious answer for everything. It is not.

Angular is a full framework. It gives you routing, HTTP, forms, dependency injection, and a strong opinion on how everything connects. For large enterprise teams where consistency matters more than flexibility, Angular is genuinely a better choice. The TypeScript integration has always been first-class. You learn Angular once and you know Angular. On large enterprise projects with 10+ developers of varying experience levels, Angular is often the better call over React. Structure matters when you cannot guarantee that everyone on the team has strong opinions about library selection.

React gives you a component model and an ecosystem. The ecosystem is vast, vibrant, and exhausting. Need routing? Pick one of several options. State management? There are five serious contenders and each has a vocal fanbase. This freedom is a real trade-off. On small teams with senior developers it produces nimble, well-tailored codebases. On large teams without strong conventions it produces sprawl.

Vue is where I would send someone who wants to learn frontend development from scratch today. The progressive enhancement philosophy is approachable. The documentation is the best in the ecosystem, maybe the best docs I have ever read for any technology. In my experience, Vue projects tend to look more similar to each other than React projects do, which matters when you are the third developer to touch a file.

But the job market for Vue is thinner in most markets. That matters more than I wish it did.

The Ecosystem Problem#

React's npm ecosystem is enormous. Almost everything you might need has a React wrapper or a React-native solution.

It is also why "React fatigue" became a phrase. The churn rate of popular libraries means that the "right" way to do routing or data fetching or forms has changed multiple times since I started. My current stack decisions as of early 2020: React Router for routing, Axios for HTTP, react-hook-form for forms, and a context-based approach for most state with Redux reserved for apps that genuinely need global state across many disconnected components.

Ask me again in six months and at least one of those will have changed. That is the deal you make with React.

The Job Market Thing#

I will be direct: React dominates the frontend job market. On any job board you look at today, React listings outnumber Vue and Angular combined. If you are learning frontend development and you want to maximize your employability, React is the pragmatic answer.

That is not the same as saying React is the best framework. It is the most widely adopted, which is a related but distinct claim.

So Why React, Really#

I chose React because it matches how I think about decomposing user interfaces. Small, composable pieces with explicit data flow. State flows down, events bubble up. It is a constraint that pays dividends at scale. I have worked on React codebases with dozens of components where I could confidently say "this thing only changes when one of these three things changes." That confidence is hard to achieve in systems with two-way binding.

The drawbacks are real. The ecosystem is fragmented. The patterns shift faster than I would like. Server-side rendering with React has historically required third-party frameworks. And the sheer volume of choices you face when starting a new project is legitimately exhausting.

But on balance, for building web applications with complex interactive UIs that need to ship fast — React has been the right tool more often than not.

Sometimes I think back to that late-night debugging session with the nested isolate scopes. My colleague was right — in React, the whole thing really would have been one function. Not because React is magic, but because it forces you to think in small, predictable pieces. That constraint is the entire point, and six years into this I still have not found a better one.

Next month I will walk through actually setting up a React project from scratch, because there are too many outdated tutorials floating around and that is a problem I can actually fix.