Are you a React developer looking to try out Angular development? Curious about how much of your knowledge is transferable? While Angular and React do have many differences, this post will show that there are some patterns and similarities that translate between the two frameworks. You might actually know more Angular already than you think you do.
The tips that follow should be seen as shortcuts to make the transition easier and act as an introduction to the fuller Angular concepts. In addition to looking at the similarities with the component-based nature of both, we’ll take a look at type systems, CLI’s, render performance and data fetching. Let's dive in!
Library vs Framework
Angular and React share some common goals making it easier to build web applications, but they achieve this in different ways. One of the key differences being that React is a UI library whereas Angular is a framework.
So, what does this mean to you as a developer?
- React is focused on updating the view layer, and relies on the react ecosystem to provide solutions for common problems such as routing, forms, etc.
- Angular has many of these features built in as part of the framework, with solutions for forms, routing, API calls, etc.
In practice, this means when working with React and wanting to build forms - you have a number of options to pick from such as building your own, or choosing between Formik, Redux-Form, or any other of the React form libraries.
On the other hand, when working with Angular, you pick from one of the form strategies that are a part of the framework, such as template forms, or reactive forms. These come with support for validation, directives, etc built in.
This is worth keeping in mind while making the switch from React to Angular; there is far less flexibility for you to make decisions about how to do certain things as Angular will have it covered, however the burden of evaluating a number of other options is taken care of for you. There is a trade off to be made.
Type system
React - Proptypes, Flow / Angular - Typescript
PropTypes for React have been around for a while now, and allow you to check the props that you pass to your components. This ensures that your component gets the data in a format it is expecting, and alerts you at runtime if there is any unexpected data types being used.
Angular allows you to do this and a lot more by using Typescript, a superset of Javascript. PropTypes checks only the props passed into your React component at run time, whereas Typescript keeps all your code strongly typed and works at build time. As we define types for all arguments, return types, variables and constants, your IDE will know much more about your code and relationships between data types, allowing for far more intelligent autocomplete and error checking (VS Code and WebStorm are great at this).
TypeScript is not an Angular technology, it's a separate language that can be used in any Javascript application, although it is required to develop in Angular.
Here's a React PropType example:
import React, { Component } from "react";
import PropTypes from 'prop-types';
class TodoItem extends Component {
render() {
return (
<div className="todo-item">
<span>{ this.props.title }</span>
<span>{ this.props.description }</span>
<div>{this.props.children}</div>
<span>{ this.props.done ? "Done" : "Todo" }</span>
</div>
)
}
}
TodoItem.propTypes = {
title: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
done: PropTypes.bool.isRequired
}
export default TodoItem;
Here's an Angular @Input() with Typescript example:
import { Component, OnInit, Input } from '@angular/core';
@Component({
selector: 'app-todo-item',
templateUrl: './todo-item.component.html',
styleUrls: ['./todo-item.component.scss']
})
export class TodoItemComponent implements OnInit {
@Input() title: String;
@Input() description: String;
@Input() done: Boolean;
constructor() { }
ngOnInit() {
}
}
CLI
React - create-react-app / Angular - Angular CLI
The simplest way to start a new React project is to use create-react-app, which sets up a React development environment with everything you need to start writing code.
npx create-react-app react-todo-app
create-react-app: Create a new app
With Angular, the Angular CLI is a great tool that helps you create a new Angular app, as well as letting you run, build, test and upgrade your app. It has more features that you will use daily when developing with Angular.
ng new angular-todo-app
Angular CLI: Create a new app
You can use it to create components, services and directives (more on these later) for you when you want them, and modifies the appropriate files in your app to reference your newly created components. You can find out all the things the CLi can help you generate at the Angular CLI docs.
ng generate component profile-card
Angular CLI: Create a new component
Components
React - extends Component / Angular - @Component
These are the building blocks of your UI, and are most like React components/Pure Components. Angular components consist of some HTML, an Angular class (*.component.ts), CSS (or SCSS), and a test spec file.
Templating
React - JSX / Angular - HTML
With React, you create your JSX template in your component, clearly showing that you are in Javascript-land and not writing standard HTML. Elements can be looped over using Javascript, and variables used as you would with any other Javascript.
Alternatively, with Angular, you write your template in an HTML file, but with Angular-specific syntax used throughout. This is useful as you can easily see what parts of the HTML have been extended by Angular.
- {{ }} - interperlation of strings
- [ ] - binding values
- ( ) - binding events
- # - template reference variables
- * - structural directives
A handy reference is the Angular docs cheatsheet.
Here is an example of a standard <a> tag with some angular syntax being used:
<a
*ngIf="routerLink"
[routerLink]="routerLink"
class="button {{modifier}}"
[class.disabled]="isDisabled"
(click)="clickLink($event)"
>
{{ linkText }}
</a>
And the same code again, annotated with what each line is doing:
<a
// Shows the element if "routerLink" is truthy
*ngIf="routerLink"
// Passes the value of "routerLink" object in component to the anchor element
[routerLink]="routerLink"
// Sets the class name and uses the value of "modifier" to set an additional class name
class="button {{modifier}}"
// Sets the class "disabled" if the component object "isDisabled" is truthy
[class.disabled]="isDisabled"
// Sends the click event to the "clickLink" function in the component
(click)="clickLink($event)"
>
{{ linkText }}
</a>
Component props
React - Props / Angular - @Input/@Output
One way that we define the API of a component is by defining what data it expects and how it communicates with the parent.
In React, you define the API of your component with props - and can pass down any valid JavaScript or component. For the component to notify the parent of a change, we generally pass down a function as a callback.
In Angular, we use @Input and @Output, where we can pass anything down as an input.
The difference is how the child communicates with the parent, that is where we define an @Output - and emit events for the parent to listen to.
todo-list.component.html (Parent component)
<div class="todo-list">
<div *ngFor="let todo of todos">
<app-todo-item
[id]="todo.id"
[title]="todo.title"
[description]="todo.description"
(onClick)="clickMarkAsDone(todo.id)"
>
</app-todo-item>
</div>
</div>
todo-list.component.ts (Parent component)
@Component({
selector: 'app-todo-list',
templateUrl: './todo-list.component.html',
styleUrls: ['./todo-list.component.scss']
})
export class TodoListComponent implements OnInit {
todos: todo[] = DEMO_TODOS;
constructor() { }
ngOnInit() {
}
clickMarkAsDone(id) {
markAsDoneApi(id);
}
}
In your child component, you need to use pass accept incoming data using @Input(), and pass events to the parent by using @Output.
todo-item.component.ts (Child component)
@Component({
selector: 'app-todo-item',
templateUrl: './todo-item.component.html',
styleUrls: ['./todo-item.component.scss']
})
export class TodoItemComponent implements OnInit {
@Input() id: Number;
@Input() title: String;
@Input() description: String;
@Input() done: Boolean;
@Output() onClick = new EventEmitter<any>();
constructor() { }
ngOnInit() {
}
click(event) {
this.onClick.emit(this.id);
}
}
todo-item.component.html (Child component)
<div class="todo-item">
<span>{{ title }}</span>
<span>{{ description }}</span>
<button
(click)="click($event)"
>
Mark as done
</button>
</div>
Render performance
React - PureComponent / Angular - onPush
As a React developer, you will have used PureComponents before in order to reduce the amount of times a component is re-rendered. Angular has a similar option to improve performance, the onPush change detection strategy. This controls what Angular checks to decide whether to re-render a component or not.
By default, Angular checks the previous and current state of all components on any data change to decide what to re-render. This causes a lot of unnecessary checks to happen, which can be avoided by using onPush change detection. This only re-renders components if the @Input() has changed, an @Output() event occurred, or if you manually tell Angular to re-render the component.
@Component({
selector: 'app-todo-item',
templateUrl: './todo-item.component.html',
styleUrls: ['./todo-item.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class TodoItemComponent implements OnInit {
...class code...
}
https://blog.angular-university.io/onpush-change-detection-how-it-works/
Child components
React - props.children / Angular - Content projection
To display child components in your React component, you can use { props.children } in your JSX template wherever the children should render.
The basic concept of rendering children is the same in Angular, you can render content that has been wrapped in your component tag by using <ng-content> as the placeholder for your content instead of { props.children }.
<div class="content-panel todo-header">
<h1 class="todo-header__title">{{title}}</h1>
<div class="todo-header__content">
<ng-content></ng-content>
</div>
</div>
There are more options with <ng-content> than props.children, though, as Angular marks these children as such and can be styled upon.
Angular ng-content and Content Projection.
Data fetching
React - fetch(), library / Angular - HTTPClient
In React you have to decide on how you want to handle fetching data from a server by using either Javascript fetch() or a library. There are multiple options available, and what you implement will depend on what the project needs to support, library features or personal preference.
HTTP calls in Angular are performed using the built-in HTTPClient module. This uses Observables (RxJx) to handle asynchronous calls, which may be unfamiliar to you if you are used to using Promises.
@Injectable({
providedIn: 'root'
})
export class TodoService {
private todosURL = 'http://localhost:3000/todos';
constructor(private http: HttpClient) { }
getTodos(): Observable<Profile> {
return this.http.get<Profile>(this.todosURL).pipe(
catchError(this.handleError<Profile>('getTodos', []))
);
}
}
The HTTPClient can be imported and used anywhere in Angular, but you will likely use an Angular Service to interact with this.
While understanding RxJs is important, that is a large topic on its own, in the meantime, here are some links to get you started:
Conclusion
Now you know that there are a few key concepts that as a React developer can give you a helping hand when starting to get into Angular development. There are other Angular basics that this post doesn’t cover, such as Directives, Services, Pipes, FormBuilder and many more, since they don’t have direct React analogies. This is because as Angular is a framework, React deals solely with the UI. Angular gives you 'more out-the-box' than React does meaning there's not a 1-to-1 relationship between Angular features and React ones.
If you're interested in learning more about Angular, check out some of our other content, here.