In mid-2016 we were starting a CRM project - a serious, complex application with real-time updates, multiple data-heavy views, and a team of four frontend developers. We spent two weeks evaluating React (with Redux) against Angular 2 (RC4 at the time). Here's what actually drove the decision.
The Context
Angular 1 had served us well on smaller projects. But Angular 2 was in release candidate stage, API still shifting, and the jump from Angular 1 was effectively learning a new framework. React had been in production at Facebook since 2013 and the ecosystem around it had stabilized by 2016.
The project: a CRM with ~60 views, complex forms, real-time notifications, and a dashboard with multiple live-updating data streams.
What Angular 2 Does Well
Angular 2 is a complete framework. It gives you:
- Routing (built-in)
- HTTP client (built-in)
- Forms (reactive and template-driven, built-in)
- Dependency injection (built-in)
- Internationalization (built-in)
- TypeScript first-class (this was genuinely ahead of its time in 2016)
For a team coming from a backend Java or C# background, Angular 2's opinionated structure feels natural. One way to do things, clear separation of concerns.
The two-way data binding with [(ngModel)] makes forms feel simple initially:
// Angular 2 form binding
@Component({
template: `
<input [(ngModel)]="user.name" />
<span>{{ user.name }}</span>
`
})
class UserFormComponent {
user = { name: '' };
}
Change user.name anywhere - the input and the span both update automatically. Magic.
Why Two-Way Binding Becomes a Problem at Scale
The magic becomes a problem when your application grows. With two-way binding, data can change from anywhere at any time. Debugging "why did this field update?" becomes genuinely hard when components share mutable state.
We had experienced this on an Angular 1 project: a form with 40 fields where tracking down why a field reset on certain interactions took hours because the state was mutated through multiple watchers across multiple components.
React's core insight: data flows in one direction, always. Parent passes data down as props. Child emits events up. State lives in a predictable place.
Redux: Predictable State for Complex Applications
For a CRM with multiple interconnected views (contact detail affects activity feed affects deal pipeline), shared global state was unavoidable. Redux gave us a single store and a strict mutation protocol:
// Redux: state mutation is explicit and traceable
const contactReducer = (state = initialState, action) => {
switch (action.type) {
case 'UPDATE_CONTACT':
return {
...state,
contacts: state.contacts.map(c =>
c.id === action.payload.id ? { ...c, ...action.payload } : c
)
};
default:
return state;
}
};
// The Redux DevTools let you time-travel through every state change
// Invaluable for debugging complex interaction sequences
The Redux DevTools browser extension was a game-changer for our debugging workflow. You could replay every action that led to a bug. With two-way binding this kind of traceability was impossible.
The Ecosystem Argument
In 2016, React's ecosystem was already richer for the specific problems we were solving:
- react-select: The best multi-select component. Nothing comparable in Angular 2 ecosystem.
- react-virtualized: Render 10,000 rows smoothly. Essential for CRM data tables.
- react-dnd: Drag-and-drop for kanban boards. Solid, production-tested.
- Recharts / Victory: Charting that integrated with React's rendering cycle.
Angular 2's ecosystem was catching up but hadn't caught up yet in September 2016.
Bundle Size and Performance
Angular 2 had a larger minimum bundle size than React in 2016. For a SaaS application behind authentication this mattered less than for a public marketing site, but it was a factor.
More importantly, React's virtual DOM diffing was well-understood and predictable. Angular 2's change detection (zone.js intercepting async operations) was more magical and harder to optimize when needed.
The Decision
We chose React + Redux + React Router. Not because Angular 2 was bad - it wasn't - but because:
- Unidirectional data flow matched the complexity of what we were building
- Redux DevTools would save us significant debugging time on a project this complex
- The component ecosystem was ahead for our specific use cases
- The team had more React experience already
Angular 2 final release came out in September 2016 (right as we were starting). By 2017 it was excellent. By 2020 it was the right choice for large enterprise teams who wanted everything built-in.
The honest 2024 retrospective: For a new project in 2024, the choice is usually Next.js (React-based) by default. Angular still has strong use in large enterprise and government projects where the opinionated structure and TypeScript-first approach are valued. The debate is less about which is better and more about team background and project requirements.
Aunimeda builds modern web frontends - from single-page applications to complex multi-locale sites.
Contact us to discuss your frontend project. See also: Web Development, Corporate Website Development