For the last two months, I have been familiarising myself with React, which was the most popular technology in 2015.
Some said that 2016 would be the year of Angular 2 — a completely rewritten, trendy JavaScript framework from Google. Previously, on my blog, I showed you what’s new in Angular 2 so, if you are new to it, you may want to check that post first.
Today, as I find these two technologies similar in some ways, I have decided to compare them.
TL;DR:
Angular 2 is strictly opinionated, and the authors advise using things like ES6 syntax. I will compare it with the most modern way of using React (e.g., combined with Babel for ES6 syntax and using JSX syntax for templates).
In my comparison, I will try to show the main similarities and differences between them and will leave the decision on which one is better entirely for you.
Compare React and Angular 2 — possible?
Good question! Many may say: “ReactJS is just a library, and Angular 2 is a comprehensive framework! You can’t compare the two…”. I completely agree.
But let’s be stubborn and go with the comparison anyway. If we still want to make a comparison, we will have to make two choices:
- we can either take React and compare all of its elements to the appropriate elements of Angular2 or
- we can compare Angular 2 as a framework with the whole ReactJS “ecosystem” — because when you create a React application, you will most likely use such libraries as react-router, Redux, Immutable, etc.
Well, I decided I prefer the second option and so will try to follow this path today.
Component model
Ok, let’s start our comparison with the most important and obvious part. Both ReactJS and Angular 2 are based on the same concept: building an app using small pieces called components
. Here's how it's usually done in ReactJS:
import React from 'react';
import 'ExampleComponent.css';
export default class ExampleComponent extends React.Component {
constructor(props) {
super(props);
this.state = { message: 'Hello from component!' };
}
render() {
return (
<div className="container">
<p>{this.state.message}</p>
</div>
);
}
}
Now, let’s look at a very similar component in Angular 2:
import { Component } from 'angular2/core';
@Component({
selector: 'component-placeholder',
templateUrl: 'app/example.template.html',
styleUrls: [ 'app/example.css' ]
})
export class ExampleComponent {
public message = 'Hello from component!';
}
As you can see above, in both cases, a component is just a JavaScript class (we use ES6 syntax — I will write about that later).
The main difference here is that in React we have to extend a base Component
and in Angular 2 we have to use a decorator @Component
. This is something that might make creating a component more difficult in Angular 2.
In React, you just have to create a component and use it in other components as if it was an HTML element (thanks to JSX syntax — again, I will write about that later).
In contrast, in Angular 2 you have to make a placeholder in an HTML template and then inform the component where it should be injected (using the selector
property of the decorator).
Another difference we can see here is that in Angular, we use templates as separate files as it was in the previous version of the framework (we can also declare a template as a string just like, for example, in directives
in Angular 1).
In contrast, with React, we just declare the template of the component inline in the JavaScript code using the JSX syntax.
Let’s stop here for the moment. Some say that separating templates and JavaScript code is better because we can achieve a separation of concerns this way.
Others disagree and say the integral component itself accomplishes that separation of concerns. I had some background in Angular when I started my journey with React. So at first, I tended to consider React components too coupled as they mixed JS and template codes in one file.
Now I have some doubts. I think I should wait for the final version of Angular 2 and do some projects with it before I can certainly say which way is better.
Templates and data binding
Ok, now that we know something about the components, we can talk more about the templates in both technologies.
As I mentioned before, in React, we declare templates inline in the render method of the component class. This is possible because of the use of JSX syntax.
We don’t have to use it — we can write everything in pure JavaScript, but this is the most streamlined way of using React and the most suitable approach to be compared with Angular 2.
JSX syntax allows you to assemble the components’ template from the other components and the HTML elements in an XML-like way. The effect is very similar to a simple HTML template.
The JSX template becomes part of React’s Virtual DOM, which is the best element in the library. When React starts rendering components in the browser, it takes all of the components first and builds an in-memory (virtual) representation of the DOM tree.
Then, on top of that, React reconciles a real DOM tree and sends it to the screen.
Because of that, reacting to any UI change is efficient because every time React re-renders the component it has to compare the Virtual DOM with the real one and change only the parts of the real DOM, which are different.
On the contrary, in Angular 2 we still have templates as separate HTML files. These templates are rendered conventionally, and every change in the UI is made just by the DOM manipulations.
When we talk about DOM manipulations, we shouldn’t forget about data binding — this is also different. In Angular 2 we still have a two-way data binding, which you can remember from the previous versions of the framework.
This means that our templates may look like this, in the example below:
<h1>Two way binding:</h1>
<div>{{message}}</div>
<label for="new-message">Type: message</label>
<input type="text" [(ngModel)]="message" id="new-message" />
<h1>Lists:</h1>
<ul>
<li *ngFor="#item of nameList">
{{item.name}}
</li>
</ul>
<h1>Directives:</h1>
<custom-directive>Loading...</custom-directive>
So first of all, have a look at line number 2. This is a property of a component object. Its value is bound to the div
element using double curly braces - this way, we can achieve a one-way data-binding, which means that in this place, we can see only the actual value of the property.
Inline number 4, we have the same property bound to the element using two-way data binding (thanks to the [(ngModel)]
attribute) - when we change the value of the of the input
the value of the property will be changed too. This is the power of the two-way data binding.
The main disadvantage of this approach is that we end up with a template full of strange custom attributes which looks even more weird than in the previous versions of the Angular framework.
How is it done in React?
Ok, so how is it done in React? Well, first of all, we don’t have two-way data binding here — we only show the actual state of the model. Let’s conjure up the component’s render method from the first example:
render() {
return (
<div className="container">
<p>{this.state.message}</p>
</div>
);
}
As you can see in line number 4, to bind the data we use single curly braces. You may also notice that we bind to the message
property of the state
object.
This is important because the value of the property changes every time (we should always do this using the setState
method of the base component class), React re-invokes the render method of the component.
This causes a change in the Virtual DOM stored in the memory, which is then compared to the real DOM, and, if it differs, the change is applied.
It sounds effortless. And it is. The main disadvantage of this approach is that nothing happens “automagically” here — we have to write more code than in two-way data binding because we have to change the state manually.
ECMAScript 6
Both ReactJS and Angular 2 support the modern syntax of ES6/ES2015 — as I wrote before, a component in both technologies is just a class.
But there is a difference — with ReactJS, we usually use Babel to transpile ES6/ES2015 code into its ES5 counterpart.
In Angular 2, we are advised to use TypeScript, which, apart from the ES6 syntax, adds static types into the language…
You can argue whether this is the right decision or not — you could say that the lack of the static typing in JavaScript is its most significant merit, so why the hell would they want to force us to stop using this benefit?
Fortunately, it’s just advice. You can use Angular 2 with Babel too, but you probably won’t. In essence, the majority of examples on the Internet are written in TypeScript, so by using this language, you’ll have an easier start.
Look for examples of React code — you can find plenty of examples written in plain ES5 JavaScript as well as those written using Babel. Many of them use JSX, but many others don’t. This may confuse someone who wants to start but has never touched it before.
Routing
This is one of those things which is an integral part of Angular 2, but in the React world is covered by an external library. The most popular is react-router, so I’ll that in my comparison.
Let’s start with the react-router. Here’s how to declare routes using this library:
ReactDOM.render(
<Router history={browserHistory}>
<Route path="/" component={App}>
<Route path="about" component={About}/>
<Route path="users" component={Users}>
<Route path="/user/:userId" component={User}/>
</Route>
<Route path="*" component={NoMatch}/>
</Route>
</Router>, document.getElementById('app'));
The code above is usually added to the entry script of the React application. As you can see, routes are configured using Route
components. Every route combines the URL of the currently displayed page with the appropriate component.
We should usually regard every component passed to the route as a single subpage — it will be added to the element with id=” app” (please see the second parameter of the render
method).
And what does it look like in the Angular 2 application? Please see this sample routing configuration:
@Component({ ... })
@RouteConfig([
{ path: '/', name: 'Home', component: Home },
{ path: '/users', name: 'Users', component: About },
{ path: '/user:id', name: 'User' component: User }
])
export class App {
...
Well… Decorators again… We just add the RouteConfig
decorator before the main application component. Here we can declare the path to recognize and inform the router system which component should be displayed.
But at what place will the component appear? In previous versions of Angular, we had an attribute data-ng-view
. Now we have a custom component:
<router-outlet></router-outlet>
You have to add the above code into the template of the main application component — the component which matches the appropriate path will be shown here.
As you can see, it generally looks pretty simple in both technologies, and both solutions work well enough.
Architecture
As React is just a library, it does not provide any architecture itself. But Facebook developers, who were the creators of this library, advise the use of Flux architecture. This provides a unidirectional data flow.
An action which contains this type, and any possible new data, is sent to the dispatcher. The dispatcher invokes callbacks registered in the stores which match this type of action (in this way, it dispatches the action to all of the stores).
Whenever the store callback is invoked, it sends a change event to inform the view. The view may change its state according to these events and re-render itself. The view can also invoke other actions, e.g., when a user interacts with it, and the flow starts again.
The Angular framework was initially implementation of the MVC pattern. In the upcoming version, the architecture is based on components.
It’s straightforward — the component and the template share data using two-way data binding, and the component also uses services directly to deal with cross-cutting concerns such as accessing data, logging, configuration, etc.
Everything which provides any data or information may be a service. In Angular 2, we also have mechanisms such as dependency injection, which help us to work in this way.
As you can see, it is not firmly opinionated it seems — they have given us the components and the services, and that’s it.
Fortunately, we can use another architecture if we want to. For example, in this article, you can see how to use Flux architecture (to be precise, they use Redux) with Angular 2, so you can do all of these kinds of things using this framework.
Summary
Phew… that’s it! I haven’t written such a long article for a long time, and I hope it’s been worth it.
I’m sure there are more parts of these two technologies which could be compared, but I’ve tried to focus on what is, in my opinion, the most important.
I’ve also tried hard not to give too much of my personal opinion here because I know deciding which technology is better can be a very controversial subject these days.
So, every time you have to make a choice, be pragmatic, consider all your needs and preferences, and make your own independent decision!
Both of these are great technologies, and both could probably apply to your project.
Useful links
Similar comparisons and other useful links:
- Angular 2 versus React: There Will Be Blood
- Angular 2, ReactJS, and the State of Modern Web Apps
- Angular 2 Application Architecture — Building Flux Apps with Redux and Immutable.js
- ReactJS For Stupid People
- Flux For Stupid People
Do you like this post? Want to stay updated? Follow us on Twitter.
Originally published at https://scalac.io on February 16, 2016.
Author Bartłomiej Dybowski