Цель этой статьи - выделить ключевые различия между Angular 2 и React. Angular 2, позаимствовавший многие идеи из React, казался неудобным гибридом Angular 1 и React. Те, кто пришел из React, будут разочарованы соглашениями Angular 2, а те, кто пришел из Angular 1, сочтут структуру компонентов незнакомой. Короче говоря, Angular 2 является значительным улучшением по сравнению с Angular 1, но не соответствует простоте других, более проверенных в боях компонентных фреймворков.

Прежде чем я углублюсь в детали, вот некоторый контекст моего опыта работы с Angular 2.

Несколько месяцев назад у меня была возможность изучить VueJs через приложение для электронных заметок. Этот опыт, хотя временами и разочаровывающий, углубил мое понимание React. Вместо того, чтобы изучать одну структуру, я начал понимать принципы разработки внешнего интерфейса, а не просто запоминать синтаксис и шаблоны.

Мой опыт работы с Angular 2 ничем не отличался. Сначала создавая базовое приложение todo в Angular 1, а затем перестраивая это же приложение в Angular 2, вы понимаете, что ключевые болевые точки пытались решить версия 2. Я не исследовал возможности маршрутизатора или хранилища данных, поэтому эти аспекты исключены из этой публикации. Angular 2 также явно рекомендует использовать TypeScript. Отличия от JavaScript незначительны, но я постараюсь указать на эти отличия по ходу дела.

Ключевые различия между Angular 2 и React

Для правильной реализации компонента в Angular 2 требуется файл component.html (с шаблоном html), файл component.ts (с бизнес-логикой) и файл module.ts (с зависимостями, импортом и объявлениями). Этот сегментированный шаблонный подход будет знаком пользователям Angular 1. Однако пользователям React он временами кажется излишне жестким и многословным.

В вашем файле module.ts для каждого компонента вы должны определить все подкомпоненты внутри этого компонента. Это отличается от React тем, что внедрение этих компонентов отделено от html, в котором вы их визуализируете, что может немного сбивать с толку.

//In React you import the dependency in a component.
import Header from './containers/Header';
//Then render that component in your render method.
render() {
    let { user } = this.state;
    return (
        <div className="App">
          <Header user={user} signOut={signOut} signIn={signIn}/>
        </div>
    );
}
//In Angular 2, you import dependencies in the module.ts file and inject them into a component with the declarations property.
@NgModule({
  declarations: [
    AppComponent,
    HeaderComponent
  ],
...})
//Then render them in the component.html file.
<div>
  <h1>{{title}}</h1>
  <HeaderComponent [user]="user"></HeaderComponent>
  <todoForm [addItem]="addItem"></todoForm>
</div>

В Angular 2 вы должны явно указать, что экспортируется из компонента, а также в каждый компонент. Синтаксис для этого может сбивать с толку, поскольку половина ресурсов в Интернете - это бета-версия с другой версией, поэтому вот пример 2 вариантов вывода значений.

//Inside your component.ts file you must explicitly define what each component is expecting to output.  Option 1 is using the @Component to define outputs in the array format.
@Component({
  selector: 'app-root', //what we want to refer to this component as
  templateUrl: './app.component.html', //html
  styleUrls: ['./app.component.css'], //scoped css
  outputs: ['list', 'addItem']
})

Я считаю этот синтаксис идеальным для передачи данных, а не для передачи функций. Для передачи функций я предпочитаю определять их с каждой функцией в классе объекта AppComponent, который затем импортируется как зависимость в файл module.ts.

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  outputs: ['list']
})
export class AppComponent {
//properties of the component are similar to state in React
  title = 'todo list';
//TypeScript sugar can define the type of each attribute and whether it is public or private, so this is a public data field with the type of any array.
  public list: any[] = [];
  Output() addItem = (item: string) => {
    this.list.push(new Item(Date.now(), item, 1));
    localStorage.setItem('list', JSON.stringify(this.list));
  }
}

Значение этого для Angular 2 состоит в том, что разработчики должны явно контролировать, какие данные оставляют компонент. Для платформы, представляющей собой корпоративное программное обеспечение для многих компаний, использующих стек MEAN, это добавляет уровень безопасности и надежности в ваш код. Для тех, кто пришел из других фреймворков, это совершенно чуждое понятие. Я привык передавать свойства через метод рендеринга в React и видел похожие шаблоны в html. Я потратил около часа, пытаясь понять, почему я не могу ничего передать, только чтобы обнаружить этот дополнительный уровень защиты.

Angular 2 требует особого синтаксиса, передающего эти свойства внутри HTML для каждого компонента.

//properties are passed with brackets
<Header [user]="user"></Header>

Функции также можно передавать как свойства.

<todoForm [addItem]="addItem"></todoForm>

События добавляются к компонентам с использованием синтаксиса скобок.

//in the todoForm.component.html file
<form (ngSubmit)="addItem($event)">
  <input [(ngModel)]="value" name="value" />
  <input type="submit" value="Submit" />
</form>

Использование скобок и скобок приведет к двухсторонней привязке данных, привязанной к свойству состояния в todoComponent значения 'value'.

@Component({
  selector: 'todoForm',
  templateUrl: './todoForm.component.html',
})
export class TodoFormComponent {
  value = '';
  @Input() addItem;
 }

При импорте свойств и функций используется тот же синтаксис, что и для вывода. Вы можете определить эти импорты в классе, как показано выше, или определить их в объекте Angular 2, как показано ниже.

@Component({
  selector: 'todoForm',
  templateUrl: './todoForm.component.html',
  inputs: [addItem]
})
export class TodoFormComponent {
  value = '';
 }

Для тех, кто знаком с React, это также может сначала расстраивать. В React я бы просто деконструировал this.props в первой строке моего рендера. Вы можете пропустить этот шаг, но для удобства чтения я бы посоветовал вам этого не делать.

render() {
    let { user } = this.props;
    return (
        <div className="Header">
          <header user={user}></header>
        </div>
    );
  }

Повсеместная тенденция при сравнении Angular 2 и React - Angular 2 требует, чтобы вы следовали соглашениям и гораздо более четко выражали свои намерения. Это можно объяснить тем фактом, что React - это скорее библиотека, чем фреймворк, что по своей сути означает, что он более гибкий.

Когда вы думаете об их целевой аудитории, это имеет смысл. Angular 1 захватил долю рынка, став одним из первых фреймворков, вышедших на рынок. Поскольку они защищают эту позицию (на процентной основе, а не на основе общего использования) для новичков, таких как emberJs, VueJs, Elm, вы поняли. Angular 2, на мой взгляд, создавался для тех первых пользователей, у которых теперь есть жизнеспособный бизнес, построенный на платформе. Явность при программировании становится все более и более важной по мере масштабирования, поэтому эти болевые точки, с которыми я сталкиваюсь с Angular 2, скорее всего, являются преднамеренными «лежачими полицейскими», призванными сэкономить время разработчиков в долгосрочной перспективе.

Angular 1 был чрезвычайно популярен, поэтому можно с уверенностью предположить, что Angular 2 будет видным фреймворком на долгие годы. Он почти в два раза быстрее, чем Angular 1, а это означает, что все компании, использующие Angular 1, скорее всего, перейдут на Angular 2. В противном случае им придется нанимать новых специалистов и перестраивать свое приложение с нуля.

Хотя мне не показался интуитивно понятный синтаксис, по причинам, упомянутым выше, я твердо верю, что изучение Angular 2 является обязательным условием для интерфейсного инженера, заботящегося о том, чтобы оставаться в курсе.