For teams considering a migration from Angular to React (referring here to Angular 2 – 7, not AngularJS), this is a quick comparison guide. By the end of this guide, you should have a good idea of how Angular concepts translate over to React.
How to create a component with Angular
First, we create the component file.
// app.component.ts
import { Component } from "@angular/core";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
})
export class AppComponent {}
And then in the associated template file, we would add in our html that’s associated with the component.
<!-- app.component.html -->
<div>
<h1>This is the title for my application</h1>
<p>Here's a little bit of text.</p>
<button>And we can't forget this button</button>
</div>
Now that we’ve created the component files, we need to add the component class to either the declaration of an associated module or to the entry components of that module.
// app.module.ts
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { AppComponent } from "./app.component";
@NgModule({
// we usually declare our components here
declarations: [AppComponent],
imports: [BrowserModule],
providers: [],
// sometimes we need to add the component here (drawers, modals, etc.)
entryComponents: [],
bootstrap: [AppComponent],
})
export class AppModule {}
How to create a component with React
In React, the template and logic are combined into one file.
// App.tsx
import React from "react";
interface IAppProps {}
interface IAppState {}
class App extends React.Component<IAppProps, IAppState> {
public render() {
return (
<div>
<h1>This is the title for my application</h1>
<p>Here's a little bit of text.</p>
<button>And we can't forget this button</button>
</div>
);
}
}
export default App;
Quick Comparison
Angular maintains separate files for the component and the rendered html. In contrast, React uses jsx (or tsx) and uses the returned html from the render method to create our DOM nodes.
Additionally, Angular requires you to register your component before using it. React doesn’t have this stipulation. You can typically do things faster in React and the future of React looks even better.
How to compose components with Angular
First, let’s add a new Typescript file for our custom component.
// customButton.component.ts
import { Component } from "@angular/core";
@Component({
selector: "app-custom-button",
templateUrl: "./customButton.component.html",
})
export class CustomButtonComponent {}
Next, we add the associated template file.
<!-- customButton.component.html -->
<button>This is a custom button</button>
And then the associated module declaration.
// customButton.module.ts
import { CustomButtonComponent } from "./customButton.component";
import { NgModule } from "@angular/core";
@NgModule({
declarations: [CustomButtonComponent],
exports: [CustomButtonComponent],
})
export class CustomButtonModule {}
Now we import that module into our app module.
// app.module.ts
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { AppComponent } from "./app.component";
import { CustomButtonModule } from "./customButton/customButton.module";
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, CustomButtonModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
And at long last, we can use the app-custom-button selector in our app’s template file.
<!-- app.component.html -->
<div>
<h1>This is the title for my application</h1>
<p>Here's a little bit of text.</p>
<app-custom-button></app-custom-button>
<button>And we can't forget this button</button>
</div>
How to compose components with React
First, we create the component file.
// CustomButton.tsx
import React from "react";
interface ICustomButtonProps {}
interface ICustomButtonState {}
export class CustomButton extends React.Component<
ICustomButtonProps,
ICustomButtonState
> {
public render() {
return <button>This is a custom button</button>;
}
}
export default CustomButton;
Next, we use the component in our app’s jsx file.
// App.tsx
import React from "react";
import { CustomButton } from "./CustomButton/CustomButton";
interface IAppProps {}
interface IAppState {}
class App extends React.Component<IAppProps, IAppState> {
public render() {
return (
<div>
<h1>This is the title for my application</h1>
<p>Here's a little bit of text.</p>
<CustomButton />
<button>And we can't forget this button</button>
</div>
);
}
}
export default App;
And then we have to…oh wait, that’s it.
Quick Comparison
With Angular, we define the component file, create an associated template, declare the component its own module, import the newly created module, and then add the component selector to the parent component’s template.
With React, we simply create the component and use it where we choose.
How to create component state with Angular
In Angular, you declare local state by adding an instance variable to your component class. Here we’re adding a dynamic bit of text to our custom button component.
// customButton.component.ts
import { Component } from "@angular/core";
@Component({
selector: "app-custom-button",
templateUrl: "./customButton.component.html",
})
export class CustomButtonComponent {
public dynamicText = "Dynamic Text";
}
To use it, we surround our variable name in double braces and place it in our template.
<!-- customButton.component.html -->
<button>{{ dynamicText }}</button>
How to create component state with React
Any component state in react is put inside an object called state. We can then use that state in our render method.
// CustomButton.tsx
import React from "react";
interface ICustomButtonProps {}
interface ICustomButtonState {
dynamicState: string;
}
export class CustomButton extends React.Component<
ICustomButtonProps,
ICustomButtonState
> {
public state: ICustomButtonState = {
dynamicState: "Dynamic Text",
};
public render() {
return <button>{this.state.dynamicState}</button>;
}
}
Quick Comparison
There’s not a whole lot of advantage here either way.
How to use component inputs with Angular
Let’s now assume that we want our custom button to be truly dynamic. We should be able to pass text in from the parent component (in this case the App component) and render our dynamic text.
In Angular, we need to use a decorator to indicate the input property name.
// customButton.component.ts
import { Component, Input } from "@angular/core";
@Component({
selector: "app-custom-button",
templateUrl: "./customButton.component.html",
})
export class CustomButtonComponent {
@Input() public dynamicText;
}
Just like before, we will add our instance variable to the associated template file.
<!-- customButton.component.html -->
<button>{{ dynamicText }}</button>
Then we can use that input to change the look of our custom button component.
<!-- app.component.html -->
<div>
<h1>This is the title for my application</h1>
<p>Here's a little bit of text.</p>
<app-custom-button
dynamicText="Text from app component"
></app-custom-button>
<button>And we can't forget this button</button>
</div>
How to use component inputs with React
In React, our inputs are called props which is short for properties. If we’re using Typescript, we need to add that property to our props interface. After adding it, we can use the property in our render method.
// CustomButton.tsx
import React from "react";
interface ICustomButtonProps {
dynamicText: string;
}
interface ICustomButtonState {}
export class CustomButton extends React.Component<
ICustomButtonProps,
ICustomButtonState
> {
public render() {
return <button>{this.props.dynamicText}</button>;
}
}
We can then use this input to change the look of our custom button component.
// App.tsx
import React from "react";
import { CustomButton } from "./CustomButton/CustomButton";
interface IAppProps {}
interface IAppState {}
class App extends React.Component<IAppProps, IAppState> {
public render() {
return (
<div>
<h1>This is the title for my application</h1>
<p>Here's a little bit of text.</p>
<CustomButton dynamicText={"Text from App component"} />
<button>And we can't forget this button</button>
</div>
);
}
}
export default App;
Quick Comparison
While both are easy to declare, the React version has one distinct advantage: Typescript. If we fail to provide a required property for our React component, we’ll get a compilation error.
The same can’t be said of Angular. It’s far too easy to misspell the input name and cause run-time issues.
It’s worth pointing out that code editor extensions exist to help mitigate these issues but React is still the winner with a better out-of-the-box solution.
How to change state with Angular
In an Angular component, we change state by modifying our input variables. In our custom button component, let’s add two quotes from the greatest TV series of all time. With each button click, we’ll toggle the displayed quote.
// customButton.component.ts
import { Component } from "@angular/core";
@Component({
selector: "app-custom-button",
templateUrl: "./customButton.component.html",
})
export class CustomButtonComponent {
private officeQuotes = [
`AND I KNEW EXACTLY WHAT TO DO.
BUT IN A MUCH MORE REAL SENSE,
I HAD NO IDEA WHAT TO DO.`,
`WIKIPEDIA IS THE BEST THING EVER.
ANYONE IN THE WORLD CAN WRITE
ANYTHING THEY WANT ABOUT ANY SUBJECT.
SO YOU KNOW YOU ARE GETTING THE BEST
POSSIBLE INFORMATION.`,
];
public selectedQuote: string = this.officeQuotes[0];
public changeOfficeQuote = () => {
if (this.selectedQuote === this.officeQuotes[0]) {
this.selectedQuote = this.officeQuotes[1];
} else {
this.selectedQuote = this.officeQuotes[0];
}
};
}
We then bind to the click event in our component template to trigger the changeOfficeQuote method.
<!-- customButton.component.html -->
<button (click)="changeOfficeQuote()">Change Office Quote</button>
<p>{{ selectedQuote }}</p>
How to change state in React
React provides a method called setState. This method merges the component’s current state with an object that we provide.
// CustomButton.tsx
import React from "react";
interface ICustomButtonProps {}
interface ICustomButtonState {
selectedQuote: string;
}
const officeQuotes = [
`AND I KNEW EXACTLY WHAT TO DO.
BUT IN A MUCH MORE REAL SENSE,
I HAD NO IDEA WHAT TO DO.`,
`WIKIPEDIA IS THE BEST THING EVER.
ANYONE IN THE WORLD CAN WRITE
ANYTHING THEY WANT ABOUT ANY SUBJECT.
SO YOU KNOW YOU ARE GETTING THE BEST
POSSIBLE INFORMATION.`,
];
export class CustomButton extends React.Component<
ICustomButtonProps,
ICustomButtonState
> {
public state: ICustomButtonState = {
selectedQuote: officeQuotes[0],
};
public changeOfficeQuote = (): void => {
let newQuote: string;
if (this.state.selectedQuote === officeQuotes[0]) {
newQuote = officeQuotes[1];
} else {
newQuote = officeQuotes[0];
}
this.setState({
selectedQuote: newQuote,
});
};
public render() {
return (
<div>
<button onClick={this.changeOfficeQuote}>
Change Office Quote
</button>
<p>{this.state.selectedQuote}</p>
</div>
);
}
}
Quick Comparison
I’ll be honest, I like Angular’s syntax slightly more. However, this seemingly small syntax differences is what makes React so performant out of the box. React only triggers change detection when props or state change.
Angular on the other hand triggers change detection on all kinds of things. This not only makes it less performant (at least out of the box) but it confuses developers.
If you’re interested, here’s a great article that compares change detection between React and Angular: https://medium.com/@n8ne00/change-detection-strategy-in-angular-and-react-aa2c5a6871fa .
How to encapsulate styles in Angular
Style encapsulation is this idea that we don’t want styles for one component leaking to other components in our application. If our styles leak, we may unknowingly break other styles.
To do this in Angular, we first create a CSS (or SCSS / SASS file) and add that file to our component metadata.
// customButton.component.ts
import { Component } from "@angular/core";
@Component({
selector: "app-custom-button",
templateUrl: "./customButton.component.html",
styleUrls: ["./customButton.component.css"],
})
export class CustomButtonComponent {}
For context, here’s what our template file looks like.
<!-- customButton.component.html -->
<button>This button now has style</button>
And then we add some styles to the corresponding CSS file.
/* customButton.component.css */
button {
background-color: blue;
}
How to encapsulate styles in React
While there’s a few approaches to this problem in React, the approach I prefer is using a CSS-in-Javascript solution like Emotion. After installing the Emotion package, you could do something like the following.
// CustomButton.tsx
import React from "react";
import { css } from "emotion";
interface ICustomButtonProps {}
interface ICustomButtonState {}
export class CustomButton extends React.Component<
ICustomButtonProps,
ICustomButtonState
> {
public render() {
const buttonClass = css`
background-color: blue;
`;
return (
<div>
<button className={buttonClass}>
This button now has style
</button>
</div>
);
}
}
The CSS method from emotion will return a unique hash (the run time class name) and generate the styles as part of some CSS file.
Quick Comparison
I actually like Angular’s solution better in this regard. This is one area where they really nailed it.
Still, the React solution has some unique upside. Let’s say that we want to change the button color based on some piece of state or props. With Emotion, and really any CSS-in-Javascript solution, we can dynamically interpolate a color based on any other properties that are available to our component.
While Angular allows something similar, the syntax is framework specific and is further away from the native Javascript API.
How to create a dynamic list in Angular
First, we add the data to our component.
// app.component.ts
import { Component } from "@angular/core";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"],
})
export class AppComponent {
public officeCharacterNames = [
"Michael",
"Dwight",
"Jim",
"Pam",
"Angela",
"Phyllis",
];
}
Next, we loop through the names using a directive.
<!-- app.component.html -->
<div>
<p>Office Characters:</p>
<ul>
<li *ngFor="let name of officeCharacterNames">
{{ name }}
</li>
</ul>
</div>
How to create a dynamic list in React
In our React equivalent, we simply map out the list of names, returning an array of html elements.
import React from "react";
interface IAppProps {}
interface IAppState {}
class App extends React.Component<IAppProps, IAppState> {
public state = {
officeCharacterNames: [
"Michael",
"Dwight",
"Jim",
"Pam",
"Angela",
"Phyllis",
],
};
public render() {
const names = this.state.officeCharacterNames.map((name, index) => {
return <li key={index}>{name}</li>;
});
return (
<div>
<p>Office Characters:</p>
<ul>{names}</ul>
</div>
);
}
}
export default App;
Quick Comparison
React is the clear winner here because it stays closer to the native Javascript APIs. You don’t need to worry about the framework-specific syntax. Instead, you can focus on writing pure Javascript.
Aside from a simpler API, React also gives us type safety. In many cases, our array contains objects with additional information. Mapping over our objects in a tsx file shows us what the objects looks like. We can’t say the same about Angular.
Conclusion
While there’s a lot more I’d like to go over, I think that’s a good start. If you’re serious about learning React, I would highly recommend their Getting Started Guide . After you have a good foundation, try moving on to more advanced concepts like context, refs, and the reconciliation algorithm.