The main differences between AngularJS (the framework) and ReactJS (the library) are in the following aspects: componentization, data binding, performance, dependency resolution, directives, and templating. Let’s look at each of these aspects separately.
With AngularJS we break the application code into several files. For example, when we create a reusable component with our own directive, controller, and template, we must describe each chunk of code in a separate file. Once we describe our directive, we then add a link to our template in the directive to couple these parts. AngularJS directives represent the template logic for your application. The template is HTML extended with Angular directives, generally written as tags or attributes. We also add controllers to provide our models with necessary $scope or context. Controllers are written in separate files as well. When we modularize our application in such a way, we can reuse our template or component in a different part of the website.
Facebook, the creator of ReactJS, chose an architecture different from that of AngularJS and similar MVC frameworks. In short, there is no “correct" structure for applications built with ReactJS.
The drawback of Angular's two-way data binding approach is its negative impact on performance. Angular automatically creates a watcher for each binding. During development, we may come to a point when an app is packed with too many watchers for bound elements.
React uses one-way data binding, meaning we are able to direct the flow of data only in one direction. Because of this, it’s always clear where the data was changed. It’s worth noting that two-way data binding was available in ReactJS before v15 thanks to ReactLink.
In order to implement a unidirectional data flow in React, Facebook created its own application architecture called Flux. Flux controls the flow of data to ReactJS components through one control point – the dispatcher. Flux's dispatcher receives an object (they call it an action) and transfers it to an appropriate store, which then updates itself. Once the update is finished, the View changes accordingly and sends a new action to the dispatcher. It's only possible to transfer an action to the store when it’s fully updated. With this concept, Flux improves the effectiveness of the code base. Based on our own experience we can say that Flux is great when you work with dynamically updated data.
The one-way data flow in ReactJS keeps complexity under control. It's much easier to debug self-contained components of large ReactJS applications than it is with similarly large AngularJS applications.
There are two things to take into consideration when we talk about Angular's performance. As we mentioned previously, Angular 1.x and higher relies on two-way data binding. This concept is based on “dirty checking," a mechanism that can make our AngularJS application laggy.
When we bind values in HTML with our model, Angular creates a watcher for each binding to track changes in the DOM. Once the View updates (becomes “dirty"), Angular compares the new value with the initial (bound) value and runs the $digest loop. The $digest loop then checks not only values that have actually changed, but also all others values that are tracked through watchers. This is why performance will decrease a lot if your application has too many watchers. This drawback is even more painful when several values (Views) are dependent on each other. Once Angular sees that the change of a value was triggered by another change of a different value, then it stops the current $digest cycle and runs it all over again.
The loop doesn't stop working until it checks all watchers and applies all necessary changes to both the View and the Model. In practice, we can bind an <input> field to different Views and Models. When the user enters new data into the field, the change may not be immediately visible. It’s better to avoid that.
Another shortcoming of the AngularJS framework is the way it works with the DOM. Unlike React, AngularJS applies changes in the real DOM in the browser. When the real DOM gets updated, the browser has to change many internal values to represent a new DOM. This also has a negative impact on application performance.
Poor performance is the main reason why Angular 2 supporters introduced the virtual Document Object Model rendered on the server and one-way data binding similarly to React. Still, Angular 2 offers two-way data binding as an option.
Now, instead of sending completely new HTML to the browser, React sends the HTML only for the changed element. This approach is much more efficient than what AngularJS offers.
As for one-way data binding, React doesn't use watchers to track changes in the real DOM. Overall, ReactJS makes it simpler to control application performance. But this doesn't mean we cannot create a fast application in AngularJS.
Angular automatically finds appropriate objects that are injected as the $routeParams, $filter, store, and $scope parameters. There are two functions that make dependency injection possible in the Angular framework: $inject and $provide.
We should also mention an issue with dependency injection in AngularJS; a small nuisance you may encounter when you run code minification.
A code minification program reduces dependency names to something like $b and $y for concision. But when executing the code, Angular will look for dependencies by their actual names, which are $scope, $filter, and store in the example above! This is when our program silently crashes. On the bright side, it's very easy to resolve this issue.
As you can see in the example below, we have declared the function TodoCtrl and passed only short names of arguments. Further below, we specifically show what to inject in our function in the necessary order. Therefore, the “s" argument stands for “$scope"; the “r" argument stands for “$routeParams", etc. Angular will find dependencies automatically. This time, pay attention to the order of the arguments.
There is also another way to pass a function and its dependencies – by using an array. The first array elements would be your dependencies followed by the function with short parameters.
Another example of how to inject dependencies into Angular module:
The difference between React and Angular with regards to dependency injection is that React doesn’t offer any concept of a built-in container for dependency injection. But this doesn't mean we have to think of a method to inject dependencies in our ReactJS project. You can use several instruments to inject dependencies automatically in a React application. Such instruments include Browserify, RequireJS, EcmaScript 6 modules which we can use via Babel, ReactJS-di, and so on. The only challenge is to pick a tool to use.
Directives and Templates
Directives in AngularJS are a way to organize our work/code around the DOM. If working with AngularJS, we access the DOM only through directives. For example, AngularJS has many standard directives, such as ng-bind or ng-app, but we can create own directives as well. And we should. This is a powerful way to work with the DOM. On the other hand, the syntax for making private AngularJS directives is rather difficult to understand.
We make our own directives in AngularJS to insert data into templates. The template must have an element with our directive written as an attribute. It's as simple as that. But AngularJS directives, if defined fully, are sophisticated. The object with settings, which we return in the directive, contains around ten properties. Such properties as templateUrl or template are easy to understand. But it’s not so clear how (and why) to define priority, terminal, scope, and other properties. Mastering the syntax of AngularJS directives may be a real challenge.
In summary, in order to bind DOM elements with Angular applications, we use directives, both standard and specific.
ReactJS doesn’t offer division into templates and directives or template logic. The template logic should be written in the template itself. To see what this looks like, open an example from GitHub. You will notice that React's component app.TodoItem is created with a standard React.createClass() method. We pass an object with properties to this function. Such properties as componentDidUpdate, shouldComponentUpdate, handleKeyDown, or handleSubmit represent the logic – what will happen with our template. In the end of the component, we usually define the render property, which is a template to be rendered in the browser. Everything is located in one place, and the JSX syntax in the template is easy to understand even if you don’t know how to write in JSX. It's clear what is going to happen with our template, how it should be rendered and what information will be presented for it by properties.
Such an approach of defining template and logic in one place is better as we spend less time initially on understanding what is happening.
To sum up, both Angular and React are great for writing single-page applications. But they are completely different instruments. Some programmers may say that React is better than Angular or vice versa. What’s really best for a given project, however, depends on how you use these instruments.
Subscribe for our newsletters