
Angular vs. React — это популярная дискуссия среди разработчиков JavaScript-приложений, и чаще всего дискуссия оказывается смещенной в сторону одной или другой технологии. Angular и React, разработанные Google и Facebook соответственно, являются двумя популярными технологиями, используемыми для создания интерактивных одностраничных приложений.
Всестороннее сравнение между Angular и React неизбежно, потому что есть определенные места, в которых они значительно перекрываются с точки зрения того, что они предлагают, то есть создание внешнего интерфейса вашего приложения и других мест, где их функциональность остается неполной, если только это не помогло третьим сторонам. тусовочная библиотека. Принятие одной технологии над другой — это вопрос того, лучше ли Angular или React решит вашу проблему и немного интуиции. В этом уроке мы сравним и сопоставим семь ключевых особенностей Angular и React.
Я — горячий сторонник подхода «сначала код» (говорят, код говорит громче, чем слова). Помня об этом, я добавил, где это возможно, примеры кода Angular и React, чтобы вы могли опираться на свою интуицию и решать, что работает для вас, а что нет. Давайте начнем.
Framework против библиотеки
Angular — это фреймворк, а React — это библиотека.
Так что это значит? Реагирование само по себе не позволит вам создать веб-приложение, потому что оно разработано для создания представлений (отсюда и «V» в MVC). Что может сделать React, так это создать основанные на компонентах представления, для которых данные могут передаваться дочерним представлениям. Чтобы заполнить этот пробел, Facebook разработал Flux , архитектурный паттерн, дополняющий React. Архитектура Flux в сочетании с React обеспечивает следующий сценарий:
- Пользователь нажимает на элемент React.
- Действие запущено. Это действие отправляется в магазин через библиотеку диспетчера.
- Магазин отслеживает состояние приложения и методы извлечения данных. Любое обновление состояния отражается в представлениях, и это помогает поддерживать представления в соответствии с состоянием приложения.
Не имеет смысла? Эта цифра должна разобраться за вас.

Angular — это фреймворк для создания клиентских приложений.
AngularJS был прочно построен на основе шаблона MVC, который разделил приложение на три разных уровня. Сочетание модели, представления и контроллера плюс дополнительная сложность, связанная с освоением директив, фабрик, сервисов и других компонентов для создания одностраничного приложения, заставили разработчиков в Google перейти к архитектуре на основе компонентов.
Но когда ваше приложение начинает расти, важно иметь прочную структуру, которая защищает бизнес-логику вашего приложения от компонентов. Будучи каркасом, Angular позволяет вам обеспечивать структурную организацию, перемещая бизнес-правила в модель предметной области (используя комбинацию классов моделей и служб) и внедряя модель в ваши компоненты посредством внедрения зависимостей.
Ниже приведен пример кода, который иллюстрирует, как бизнес-логика инкапсулируется внутри модели User и службы User, а также вне нашего компонента.
|
1
2
3
4
5
6
7
8
9
|
/* Path: /app/models/User.ts */
export class User {
id: number;
username: string;
password: string;
firstName: string;
lastName: string;
}
|
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
/* /app/services/user.service.ts */
import { Injectable } from ‘@angular/core’;
import { Http } from ‘@angular/http’;
import { User } from ‘../models/User’;
@Injectable()
export class UserService {
constructor(private http: Http) { }
getAll() {
// API to return all users
}
create(user: User) {
//API call to create user
}
update(user: User) {
//API call to update user
}
delete(id: number) {
//API call to delete user
}
}
|
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
/* Path: /app/page/page.component.ts */
import { Component } from ‘@angular/core’;
import { User } from ‘../models/User’;
import { UserService } from ‘../services/user.service’;
@Component({
templateUrl: ‘page.component.html’
})
export class PageComponent {
currentUser: User;
users: User[] = [];
constructor(private userService: UserService) {
//Dependency is Injected inside the constructor’s arguments
deleteUser(id: number) {
this.userService.delete(id).subscribe(() => { #Do Something});
}
private loadAllUsers() {
this.userService.getAll().subscribe(users => { #Do something else });
}
}
|
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
<!—Path: /app/home/page.component.html —>
<div class=»title»>
<h2>All users:</h2>
<ul>
<li *ngFor=»let user of users»>
{{user.username}} ({{user.firstName}} {{user.lastName}})
— <a (click)=»deleteUser(user.id)»>Delete</a>
</li>
</ul>
</div>
|
Компонентный подход
Компоненты являются самым основным строительным блоком пользовательского интерфейса в приложении Angular. Приложение Angular — это дерево компонентов Angular.
Какие компоненты? В Angular компоненты — это классы TypeScript, над @Component отмечен декоратор @Component . Более того, внутри этих декораторов мы можем определить, что Angular называет метаданными, которые включают в себя шаблон, стили, селекторы и так далее.
Иерархия компонентов в Angular разработана таким образом, что вы можете связать структуру и функциональность в рамках одной сущности. Вот высокоуровневый архитектурный обзор компонентов и как это связано со всем остальным в Angular.

Обмен данными между компонентами возможен путем вложения компонентов, как показано ниже.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
/* UserParentComponent.ts */
import { Component } from ‘@angular/core’;
// The <user-child> selector is nested inside <user-parent>.
@Component({
selector: ‘user-parent’,
template: `
<h2>There are {{users.length}} registered users {{status}} now</h2>
<user-child *ngFor=»let user of users»
[user]=»user»
[status]=»status»>
</user-child>
`
})
export class UserParentComponent {
users: { id: number, name: string }[] = [
{ «id»: 0, «name»: «Chris» },
{ «id»: 1, «name»: «Dwayne» },
{ «id»: 2, «name»: «Eve» }
];
status: string = «online»;
}
|
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
/* UserChildComponent.ts */
import { Component, Input } from ‘@angular/core’;
// Input properties are adorned with @decorators
// user & status are input properties
@Component({
selector: ‘user-child’,
template: `
<h2>{{user.name}}</h3>
<p> id : {{user.id}} </p>
<p> Status: {{status}} </p>
`
})
export class UserChildComponent {
@Input() user: { id: number, name: string };
@Input() status: string;
}
|
Концепция компонентов глубоко укоренилась в React, как и в Angular. Вызовы Facebook Реагируйте на библиотеку компонентов, которая позволяет создавать интерактивные пользовательские интерфейсы. Однако, в отличие от Angular, компоненты React являются просто функциями JavaScript с произвольным числом входов и выходов . В приведенном ниже коде показан компонент, определенный с помощью функции JavaScript и класса ES6.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
// Writing components using JavaScript functions
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
// Writing components using ES6 Class
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
|
Отныне мы будем придерживаться стандартов ES6 для составления компонентов, потому что именно это рекомендует Facebook. Каждый компонент React принимает произвольное количество входных данных, которые хранятся внутри объекта с именем props .
Он также имеет метод render , и, как следует из названия, этот метод определяет, что будет отображаться при вызове компонента. Каждый компонент поддерживает внутреннее состояние (через this.state ), и каждый раз, когда состояние изменяется, функция рендеринга этого компонента вызывается снова.
Особенности языка: TypeScript против ES6
Угловые приложения написаны на TypeScript, который является надмножеством ECMA2015 и использует транспортер для компиляции вашего строго типизированного файла .ts в простой файл .js. TypeScript предлагает языковые расширения, предназначенные для облегчения написания на JavaScript, а также связывает информацию о типах с сущностями JavaScript, чтобы обеспечить проверку типов и улучшить рабочий процесс разработки.
Некоторые из ключевых функций TypeScript включают необязательную статическую типизацию и поддержку интерфейсов, классов и декораторов. (Декораторы — это функции с префиксом «@», за которыми сразу следует класс, параметр или свойство.)
Давайте погрузимся в React, не так ли? В этом примере кода очевидна одна из важных особенностей языка React.
|
01
02
03
04
05
06
07
08
09
10
11
|
function Tweet(props) {
return(
<div className=»tweet»>
<img src=»http://twitter.com/some-avatar.png» className=»tweet__avatar» />
<div className=»tweet__body»>
<p>This is a tweet.</p>
</div>
</div>
);
}
|
Разве это не здорово? React позволяет встраивать теги XML / HTML в файл JavaScript, и это делается с помощью JSX, который предлагает возможность расширения синтаксиса для JavaScript. Мы должны использовать такой компилятор, как Babel, который компилирует наш JSX-код в JavaScript, понятный браузерам. Приведенный выше код сводится к следующему:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
«use strict»;
function Tweet(props) {
return React.createElement(
«div»,
{ className: «tweet» },
React.createElement(«img», { src: «http://twitter.com/some-avatar.png», className: «tweet__avatar» }),
React.createElement(
«div»,
{ className: «tweet__body» },
React.createElement(
«p»,
null,
«This is a tweet.»
)
)
);
}
|
Хотя использование JSX рекомендуется, вы можете придерживаться React.createElement() если вы против идеи встраивания HTML-тегов в JavaScript.
Кроме того, вы можете использовать либо стандарты ES6, либо традиционную форму JavaScript при работе с React. Хотя ES6 является относительно новым, он добавляет множество функций, таких как классы, функции стрелок, литералы шаблонов, деструктурирование и использование let и const. Единственный недостаток, о котором я могу думать, это то, что он добавляет немного стандартного кода, такого как необходимость вызывать super() каждый раз, когда вы вызываете constructor() , и что он не связывает автоматически методы обработки событий с this .
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
class User extends React.Component {
constructor(props) {
//bloat code alert
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleInputChange = this.handleInputChange.bind(this);
}
handleSubmit(user) {
//Method to handle submit
}
handleInputChange(user) {
//Method to handle input
}
render() {
return (
<div>
<UserRegistration
onSubmitSuccess={this.handleSubmit} onInputChange={this.handleInputChange} />
</div>
);
}
}
|
Проверка типов в Angular против PropTypes в React
Проверка статического типа выполняется во время компиляции. Компилятор предупреждает вас о возможных несовпадениях типов и обнаруживает определенные ошибки, которые в противном случае остались бы незамеченными. Кроме того, определение контракта для переменной, свойства или параметров функции может привести к более удобочитаемому и поддерживаемому коду.
Объявления переменных и функций делаются более выразительными, объявляя их типы данных. Вы можете прочитать больше о различных примитивных типах данных в документации TypeScript .
|
01
02
03
04
05
06
07
08
09
10
|
let isLoggedIn: boolean = false;
let id: number = 10;
let name: string = «Davis»;
let list: number[] = [1, 2, 3];
enum Color {Red, Green, Blue};
let c: Color = Color.Red;
let bucket: any = 4;
bucket = «I can be a string»;
bucket = false;
|
Определение сигнатуры API с использованием интерфейса делает код менее двусмысленным и более легким для понимания. Интерфейс служит в качестве краткого руководства по началу работы, которое поможет вам сразу приступить к работе с кодом и сэкономит время, затрачиваемое на чтение документации или фактическую реализацию библиотеки.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
interface ButtonSettings {
text: string;
size?: { width: number;
color?: string;
}
function createButton(settings: ButtonSettings) { … }
createButton({ text: ‘Submit’ });
createButton({ text: ‘Submit’, size: { width: 70, height: 30 }});
createButton({ text: ‘Submit’, color: 43);
createButton({ text: ‘Submit’, size: { width: 70 });
createButton({ color: ‘Blue’});
|
Ключевое слово type в TypeScript может использоваться для создания псевдонима для типа. Затем вы можете создавать новые типы, которые являются объединением или пересечением этих примитивных типов.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
//Union Types
type Age = number |
function getAge (age: Age): string {
return `You are ${age}!`;
}
let ofSusan: Age =21;
let ofTyler: Age = ‘thirty one’;
getAge(ofSusan);
getAge(ofTyler);
//Intersection Types
interface Name{
name(firstName: string, lastName: string): string;
}
interface Age {
age(current: number): number;
}
// assign intersection definition to alias User
type User = Name & Age;
function createUser (testUser: User) {
testUser.name(«David»,»John»);
testUser.age(99);
testUser.address();
|
React имеет ограниченную поддержку для проверки типов, потому что базовый ES6 не поддерживает его. Тем не менее, вы можете реализовать проверку типов с помощью библиотеки prop-types разработанной командой React. Проверка типа props компонента, чтобы проверить, является ли это строкой, может быть выполнена, как показано ниже.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
import PropTypes from ‘prop-types’;
//importing prop-types library
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
<P> My age is, {this.props.age} </h2>
);
}
}
Greeting.propTypes = {
name: PropTypes.string;
age: PropTypes.number;
};
|
Но prop-types не ограничиваются строками, числами и логическими значениями. Вы можете сделать намного больше, как описано в документации библиотеки prop-types. Однако, если вы серьезно относитесь к статической проверке типов, вам следует использовать что-то вроде Flow , который является статической библиотекой проверки типов для JavaScript.
Леса: Угловой CLI против создания-реагировать-приложение
Начать проект с нуля на первый взгляд может показаться забавным. Однако процесс настройки структуры каталогов, написания стандартного кода для компонентов и загрузки приложения является бесполезным и непродуктивным упражнением. Ваша стратегия должна заключаться в том, чтобы как можно быстрее справиться с этим и сосредоточиться на фактической разработке приложения. Благодаря Google и Facebook у вас есть инструменты для удобного создания и создания приложений.
Настроить Angular-CLI для angular и создать-реакцию-приложение для React просто, используя npm.
|
1
2
3
4
5
6
7
|
// Angular CLI
$ npm install -g @angular/cli
// create-react-app
$ npm install -g create-react-app
|
Чтобы создать новое приложение Angular, вы должны использовать следующую команду:
|
1
2
|
$ ng new PROJECT-NAME
$ ng serve
|
Но это не так. Команда ng generate позволяет вам генерировать компоненты, маршруты, каналы, директивы и сервисы.
|
1
2
3
4
5
6
7
8
|
$ ng generate component Page
installing component
create src\app\page\page.component.css
create src\app\page\page.component.html
create src\app\page\page.component.spec.ts
create src\app\page\page.component.ts
update src\app\app.module.ts
|
Angular CLI может сделать гораздо больше, например, создать сборку приложения Angular, команды для запуска модульных тестов и сквозного тестирования. Вы можете прочитать больше об этом на GitHub .
С другой стороны, create-react-app является официально поддерживаемым способом создания приложения React без каких-либо файлов конфигурации.
$ npm install -g create-react-app
Это должно создать функциональное приложение React со всеми зависимостями Babel и webpack. Вы можете запустить приложение в своем браузере, используя npm start .
Вы можете найти сценарии, доступные для приложения реагирования, в файле package.json .
|
1
2
3
4
5
6
7
|
«scripts»: {
«start»: «react-scripts start»,
«build»: «react-scripts build»,
«test»: «react-scripts test —env=jsdom»,
«eject»: «react-scripts eject»
}
}
|
Привязка данных: двусторонняя привязка против однонаправленной привязки
Привязка данных — это функция, которая позволяет синхронизировать данные между состоянием приложения (моделью) и представлением. В односторонней процедуре привязки данных любое изменение в состоянии приложения автоматически обновляет представление. Напротив, двусторонняя привязка данных связывает вместе свойства и события в рамках одной сущности, то есть любая модификация модели обновляет представление и наоборот.
В React свойства передаются от родительских компонентов к дочерним, что известно как однонаправленный или нисходящий поток данных. Состояние компонента является инкапсулированным и недоступным для других компонентов, если оно не передается дочернему компоненту в качестве реквизита, т.е. состояние компонента становится реквизитом дочернего компонента.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
class UserChild extends React.Component {
render() {
let userData = this.props.users.map( (user) => {
return (<p> <strong>{user.id} </strong> : {user.name} </p>);
});
return (
<div>
<h2> Hello.
{userData}
</div>
);
}
}
class UserParent extends React.Component {
constructor() {
super();
//State gets defined here
this.state = {
status: «Online»
}
}
render() {
return (
<div>
<UserChild users={this.props.users} status={this.state.status} />
</div>
);
}
}
var USERS = [
{ «id»: 0, «name»: «Chris» },
{ «id»: 1, «name»: «Dwayne» },
{ «id»: 2, «name»: «Eve» }
];
ReactDOM.render(
<UserParent users={USERS} />,
document.getElementById(‘container’)
);
|
Но что, если вам нужно распространять данные через дерево компонентов? Это делается с помощью дочерних событий и родительских обратных вызовов. Документация React содержит хороший пример, который касается такого сценария.
Методы привязки данных, доступные в Angular, являются одними из нескольких функций, которые делают его интересным. Angular имеет встроенную поддержку для интерполяции, односторонней привязки, двусторонней привязки и привязки событий.
Интерполяция — это самый простой способ связать свойство вашего компонента внутри текста между вашими тегами HTML и назначениями атрибутов.
<p>Welcome back {{currentUser.name}}!</p>
Привязка свойств аналогична интерполяции в том смысле, что вы можете привязать свойства элементов вашего представления к свойствам компонента. Привязка свойств способствует взаимодействию компонентов и идентична передаче реквизитов в React.
<img [src]="userImgUrl">
<user-child [user]="currentUser"></user-child>
Привязки событий позволяют поток данных в противоположном направлении, то есть от элемента к компоненту. Здесь click является целевым событием, а справа у нас есть метод onSave() который вызывается при возникновении события.
<button (click)="onSave()">Save</button>
Но наиболее важной особенностью является двустороннее связывание с использованием [(ngModel)] . Это объединяет привязку свойства и привязку события в одну директиву и особенно полезно с формами и полями ввода.
|
1
2
3
4
|
<div>
<label>name: </label>
<input [(ngModel)]=»hero.name» placeholder=»name»>
</div>
|
Рендеринг на стороне сервера
Рендеринг на стороне сервера является традиционной техникой рендеринга. Здесь сервер возвращает весь HTML-файл по запросу, а браузеру остается просто показать его пользователю. Рендеринг на стороне клиента, с другой стороны, возвращает простой HTML-документ, таблицу стилей и файл JavaScript.
JavaScript делает последующие запросы на визуализацию остальной части сайта с помощью браузера. React, Angular и все другие современные библиотеки интерфейса JavaScript являются хорошими примерами рендеринга на стороне клиента. Это очевидно, если вы просматриваете источник вашего приложения Angular / React.
Но у рендеринга на стороне клиента есть недостатки: он плохо работает для SEO и возвращает неполный HTML-контент, когда вы делитесь своей ссылкой на сайтах социальных сетей. В Angular есть решение под названием Angular Universal, которое позаботится о том, чтобы сделать вашу поисковую систему дружественной для поисковых систем и социальных сетей. Это библиотека, созданная командой Angular, и ее использование определенно приветствуется.
В Universal используется технология предварительного рендеринга, при которой весь сайт сначала отображается с сервера, а через пару секунд пользователь переключается на рендеринг на стороне клиента. Поскольку все это происходит под капотом, пользователь не замечает ничего другого.
Если вы используете React с Redux, в документации по Redux есть хорошее руководство по настройке рендеринга сервера. Вы также можете настроить React для рендеринга с сервера, используя компоненты BrowserRouter и StaticRouter доступные в библиотекеact react-router . Вы можете прочитать больше об этом в этой средней статье . Но если вы заинтересованы в производительности и оптимизации, вы можете попробовать next.js , библиотеку для SSR в React.
Завершение
Сравнение полноценной, многофункциональной инфраструктуры с надежной библиотекой пользовательского интерфейса может показаться несправедливым. Однако они представляют собой передовые технологии JavaScript, используемые для создания интерактивных одностраничных приложений, и в этой связи эта статья должна помочь вам выбрать одно из них.
Что вы думаете о Angular vs. React? Делитесь ими в комментариях ниже.