back to blog
    Dec 2025·10 min

    Angular Signals vs React Hooks: A Practical Comparison

    Benchmarks, DX comparison, and real-world patterns for both reactivity models. Which one wins?

    AngularReactPerformance

    Both models solve derived state and effects. They differ in what they track: signals track values, hooks track renders. Almost every practical difference follows from that one sentence.

    The same feature, twice

    ts
    // Angular — dependencies are discovered from reads, granularity is the signal
    @Component({
      selector: "app-cart",
      template: `
        <input [value]="query()" (input)="query.set($any($event.target).value)" />
        <p>{{ visible().length }} of {{ items().length }} — {{ total() | currency }}</p>
      `,
    })
    export class CartComponent {
      items = signal<Item[]>([]);
      query = signal("");
    
      visible = computed(() =>
        this.items().filter((i) => i.name.toLowerCase().includes(this.query().toLowerCase())),
      );
      total = computed(() => this.visible().reduce((s, i) => s + i.price * i.qty, 0));
    }
    tsx
    // React — dependencies are declared, granularity is the component
    function Cart({ items }: { items: Item[] }) {
      const [query, setQuery] = useState("");
    
      const visible = useMemo(
        () => items.filter((i) => i.name.toLowerCase().includes(query.toLowerCase())),
        [items, query],
      );
      const total = useMemo(() => visible.reduce((s, i) => s + i.price * i.qty, 0), [visible]);
    
      return (
        <>
          <input value={query} onChange={(e) => setQuery(e.target.value)} />
          <p>{visible.length} of {items.length} — {format(total)}</p>
        </>
      );
    }

    What the numbers said

    On a 5,000-row grid with a single cell update, signals win clearly: Angular re-evaluated one computed and patched one DOM node, while React re-rendered the row subtree unless I memoised aggressively. On full-list replacement the two converged — that work is dominated by DOM, not by reactivity.

    • Signals: fine-grained updates for free, no dependency arrays, no stale-closure bugs.
    • Hooks: a smaller mental model at the component level, an enormous ecosystem, and predictable render semantics.
    • Both punish untracked mutation — the failure modes just look different.

    Neither wins outright. If your app is dashboard-shaped with dense high-frequency updates, signals remove a category of manual memoisation. Otherwise pick the ecosystem you can hire for.