Back to all articles
TECHNICAL

What Actually Transfers When You Switch Frameworks (And What Doesn't)

The framework never decided where my state lived. I did. React and Angular just gave me different syntax for the same decision.

TECHNICAL

The framework never decided where my state lived. I did. React and Angular just gave me different syntax for the same decision.

I've shipped enterprise work in both stacks, not as a side project, as the actual job. And the honest version is: most of what people argue about in "Angular vs React" threads is syntax. The part that actually matters, the part that decides whether a codebase stays sane after eighteen months, has almost nothing to do with which framework is on the label.

Abstract diagram showing two different framework paths converging into one shared architectural decision
Different syntax, same underlying decision.

Where state lives is a decision, not a default

In Angular, I reach for a service with RxJS or a signal, sometimes NgRx if the shared state is genuinely complex enough to need it. In React, that becomes a hook, Context, or Zustand. Different words, same question every time: does this piece of state belong to one component, or does something else need to see it too.

That question is the actual work. The syntax is just where you write the answer down.

// Angular: state lives in a service, above the component
@Injectable({ providedIn: 'root' })
export class CartService {
  private readonly items = signal<CartItem[]>([]);
  readonly itemCount = computed(() => this.items().length);

  add(item: CartItem) {
    this.items.update(current => [...current, item]);
  }
}
// React: same decision, different syntax
function useCart() {
  const [items, setItems] = useState<CartItem[]>([]);
  const itemCount = useMemo(() => items.length, [items]);

  const add = (item: CartItem) => {
    setItems(current => [...current, item]);
  };

  return { items, itemCount, add };
}

Neither snippet is interesting on its own. What's interesting is that I made the same call in both: cart state lives one layer above the component that renders a single line item, and the count is derived, not stored separately. That decision came first. The hook and the service are just where I wrote it down.

What I noticed switching between the two: the mistake I used to make in Angular, pushing state one layer too high "just in case", is the exact same mistake I can make in React with a Context provider wrapped around half the app because pulling it down later felt like more effort than lifting it up now. The framework didn't cause that habit. I did. And fixing it in one stack taught me to catch it faster in the other.

Boundaries, briefly, because I already wrote about this

I wrote a full piece on this recently, about Nx tags and enforced module boundaries. The short version for React: the tooling looks different, no built-in tags and constraint rules the way Nx has them. Most teams lean on folder structure, something like eslint-plugin-boundaries to enforce which folders can import from which, or just team discipline if nobody's set that up yet. But the underlying question is identical. Does this feature reach into something it doesn't own. In Angular I got used to the linter catching that for me. In React, more often than not, I have to build that guardrail myself, or accept it lives in code review instead of the build. That's a real difference in how much the tool protects you, not a difference in whether the boundary matters.

Testing, the part I trust least to transfer cleanly

This is where I'd push back on myself if I tried to claim everything carries over. Testing Angular components and testing React components rewards genuinely different instincts. Angular's DI makes it almost too easy to mock a service and test a component in isolation, sometimes too isolated, testing wiring instead of behavior. React, especially with hooks, pushed me toward testing more from the outside, closer to what the user actually does, because half the "internals" don't have a clean seam to mock in the first place.

I don't think one approach is better. I think they taught me different defaults, and I catch myself defending the wrong default when I'm tired and just want the test to pass.

What honestly doesn't transfer

I'd be lying if I said it's all the same underneath. The change detection model is not a detail, it shapes how you think about performance from the first day. JSX and templates are not interchangeable habits, they train a different relationship between markup and logic. And the ecosystem conventions, how a React team expects you to structure a feature folder versus how an Angular team expects a module, are learned muscle memory, not portable knowledge. You can transfer the thinking. You still have to relearn the hands.

The actual takeaway

If you're hiring, or being hired, based on which framework is on the resume, I understand why, the tooling is real and it takes time to get fluent in either one. But the skill that actually protects a codebase, knowing where a piece of state should live, where a boundary needs to hold, what a test should actually be checking, that skill moved with me. It didn't reset when I changed which framework I was writing it in.


I'm going deeper into the state question specifically in the next piece, where state actually lives in a large Angular app, same honesty, more architecture. Worth subscribing if this kind of thing is useful to you.

React and Angular gave me different syntax for the same decisions: where state lives, where a boundary holds, what a test should check. The framework never decided those. I did.

On technical
#technical
NEWSLETTER

Get new posts by email

Frontend architecture, product engineering and AI. No spam.

Vitalii KasapVitalii KasapSenior Frontend & Product Engineer