Skip to content
Sahil Durgia/ full-stack
2 min readReact

Why React Won: A Technical History of the Frontend Framework Wars

Backbone, Ember, Angular.js, then React — a technical, not nostalgic, account of what each generation of frontend framework actually got right and wrong.

Reactfrontend historyframeworks

React didn't win in a vacuum — it won a real technical argument against real predecessors, each of which got something right and something wrong. Knowing what they got wrong is what actually explains React's specific design choices.

Backbone.js: structure, but no rendering opinion

Backbone gave the frontend Models and Views — real structure, a real improvement over jQuery spaghetti. What it didn't give you was an opinion on *how* a view re-renders when a model changes. Most Backbone apps ended up hand-writing the same imperative DOM-patching jQuery already had, just organized slightly better. Structure without a rendering model doesn't actually solve the underlying problem from the previous post.

Angular.js (1.x): two-way binding, and its actual cost

Angular.js's two-way data binding was genuinely impressive for its time — change the model, the view updates; change the view (a form input), the model updates, automatically, no manual wiring. The cost showed up at scale: with enough bindings on a page, Angular's dirty-checking (its mechanism for detecting what changed) had to walk the entire watched-value tree, repeatedly, to figure out what needs updating. Convenient for a small app; a measurable performance tax on a big one.

Ember: opinionated, and that was both the strength and the ceiling

Ember's "convention over configuration" produced genuinely consistent, maintainable codebases across a team — a real strength. The cost was flexibility: adopting Ember meant adopting its entire worldview, and integrating a component that didn't fit Ember's conventions was disproportionately hard compared to a library with a smaller, more composable surface area.

What React actually did differently

One-way data flow (data flows down, events flow up — no ambient two-way binding to reason about), a render function that's a pure description of "what the UI should look like given this state" rather than an imperative mutation sequence, and — critically — no opinion on anything outside rendering: no built-in router, no built-in state management, no built-in HTTP client. That last part reads as a limitation and was actually the winning move: it meant React could be adopted incrementally, one component at a time, inside an existing jQuery or Backbone app, instead of demanding a full-app rewrite. Ease of incremental adoption, not raw technical superiority alone, is a real and underrated part of why it actually won in practice.

Keep reading
Next: the virtual DOM, explained

Part 3 of the why-React series.