React vs. Angular 2

19 хв. читання
12 листопада 2021

Це стаття-огляд двох популярних інструментів для front-end веб-розробки – React і Angular 2. Фреймоворки будуть оцінюватися на основі їх підходів до побудови структури додатків, рівня прийняття користувачами, продуктивності та можливості інтеграції з різними платформами.

Метою даної статті є виділення основних відмінностей, аби зрозуміти схожість між цими двома інструментами.

Потік розвитку

Angular 2

Angular 2 дуже близький до повноцінного фреймворку – він "з коробки" йде з багатьма вбудованими блоками, які охоплюють більшість поширених сценаріїв при розробці веб-додатків. Існує також чіткий поділ ролей різних елементів:

Сервіси (Services) - елементи, які використовують дані з API або розділяють стан між декількома компонентами.

Компоненти (Components) - будівельні блоки UI, які використовують сервіси. Можуть бути вкладені один в одного через структурні директивні селектори.

Директиви (Directives) - поділяються на структурні та атрибутні директиви. Структурні директиви (наприклад,*NgFor) впливають на DOM (Document Object Model), тоді як директиви атрибутів є частиною елементів і контролюють їх стиль і стан.

Пайпи (Pipes) - використовуються для форматування того, як відображаються дані у вікні перегляду.

Модулі (Modules)- експортоспроможні блоки додатку, які ізолюють компоненти, директиви, пайпи, сервіси і маршрути разом.

React

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

Структура коду

Angular 2

Angular 2 написаний на TypeScript, це мова-надбудова над JavaScript, розроблена Microsoft. Мова вводить нові типи, нові структури даних і більше об'єктно-орієнтованих можливостей, що робить код легшим для читання в порівнянні з чистим JavaScript. Спочатку синтаксис TypeScript був навмисно подібний C#. Проте, останнім часом TypeScript використовує стрілку(=>) та інший ES6-подібний синтаксис, що робить TS схожим більше на ES6.

Використання TypeScript робить створення Angular 2-додатку якимось нудним, так як TypeScript вводить додаткові складнощі для конфігурації.

React

React покладається на JSX (Java Serialization to XML), XML використовується для синтаксичного розширення JavaScript і HTML. З точки зору синтаксису і структури, JSX виглядає як JavaScript і, здається, зливається в HTML легше. Це дозволяє змішувати змінні і структури даних з JavaScript всередині розмітки HTML.

Для того, щоб отримати більш чітке порівняння у коді між React і Angular 2, ми будемо порівнювати код TODO додатка.

Обидві програми використовують Webpack для розробки і перегрупування.

З точки зору структури додатка, як для React, так і для Angular 2 потрібно два файли - ToDoList, який представляє собою список завдань і Todo, який представляє одну задачу. Давайте проаналізуємо компоненту ToDoList (todolist.component.ts для Angular 2 і todo-list.js для React, відповідно) крок за кроком, зверху вниз:

Імпорт

Angular 2

import {Component} from '@angular/core';
import {bootstrap} from from '@angular/platform-browser-dynamic';;
import {TodoCmp, ITodo} from "./todoCmp";

React

import React from 'react';
import ReactDOM from 'react-dom';
import Todo from './todo';

Ініціалізація компонента

Основні дії помічені за допомогою коментарів.

Angular 2

// Використовується для визначення властивостей стану в класі TodoListCmp.
// Обидві властивості є необов'язковими, але їм надається перевага,
// так як такий код легше підтримувати.
interface IState {
  todos?: ITodo[];
  todoText?: string;
}

// Цей синтаксис називається Декоратор і схожий
// на Анотацій в інших мовах. Декоратори
// планують включити до ES2016.
@Component({
  selector: 'todo-list',
  template:` ` /*Сюди можна додати розмітку для шаблону. В якості альтернативи, ви можете посилатися на HTML файл, використовуючи templateUrl */
})

export class TodoListCmp {
  private static lastId: number = 0;
  private state: IState;

  constructor() {
    this.state = {
      todos: [
        TodoListCmp.createTodo('learn Angular', true),
        TodoListCmp.createTodo('build an Angular app')
      ]
    };
  }

React

let lastId = 0; // у класі в ES6 немає статичних властивостей

class TodoList extends React.Component {
  constructor() {
    super(); // потрібно зробити виклик перед доступом до "this"
    this.state = {
      todos: [
        TodoList.createTodo('learn React', true),
        TodoList.createTodo('build a React app')
      ]
    };
  }

Створення елемента

Angular 2

static createTodo(
    text: string, done: boolean = false): ITodo {
    return {id: ++TodoListCmp.lastId, text, done};
}

onAddTodo(): void {
    const newTodo: ITodo =
      TodoListCmp.createTodo(this.state.todoText);
    this.state.todoText = '';
    this.state.todos = this.state.todos.concat(newTodo);
}

React

static createTodo(text, done = false) {
    return {id: ++TodoList.lastId, text, done};
}

onAddTodo() {
    const newTodo =
      TodoList.createTodo(this.state.todoText);
    this.setState({
      todoText: '',
      todos: this.state.todos.concat(newTodo)
    });
}

Як показано вище, процес створення майже однаковий для обох інструментів, але у React трохи коротший і потрібно менше логіки для розробників.

Визначення станів елементів

Angular 2

get uncompletedCount(): number {
    return this.state.todos.reduce(
      (count: number, todo: ITodo) =>
        todo.done ? count : count + 1, 0);
}

React

get uncompletedCount() {
    return this.state.todos.reduce(
      (count, todo) =>
        todo.done ? count : count + 1, 0);
}

Реагування на зміни

Angular 2

onArchiveCompleted(): void {
    this.state.todos =
      this.state.todos.filter((t: ITodo) => !t.done);
}

onChange(newText: string): void {
    this.state.todoText = newText;
}

onDeleteTodo(todoId: number): void {
    this.state.todos = this.state.todos.filter(
      (t: ITodo) => t.id !== todoId);
}

onToggleDone(todo: ITodo): void {
    const id: number = todo.id;
    this.state.todos = this.state.todos.map(
      (t: ITodo) => t.id === id ?
        {id, text: todo.text, done: !todo.done} : t);
}

React

onArchiveCompleted() {
    this.setState({
      todos: this.state.todos.filter(t => !t.done)
    });
}

onChange(name, event) {
    this.setState({[name]: event.target.value});
}

onDeleteTodo(todoId) {
    this.setState({
      todos: this.state.todos.filter(
        t => t.id !== todoId)
    });
}

onToggleDone(todo) {
    const id = todo.id;
    const todos = this.state.todos.map(t =>
      t.id === id ?
        {id, text: todo.text, done: !todo.done} :
        t);
    this.setState({todos});
}

Самоналаштування

Angular 2

//В Angular 2, частини логіки
//додатку, яка відповідає за певну особливість
//інкапсулюється в модулі
import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { TodoListCmp }   from './todoList.component';
@NgModule({
  imports:      [ BrowserModule ],
  declarations: [ TodoListCmp ],
  bootstrap:    [ TodoListCmp ]
})
export class AppModule { }
//Модуль Angular може імпортувати функціональності з інших модулів та експортувати деякі вбудовані блоки до інших //модулів.
// src/main.ts

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

//Модуль вже самоналаштований, самоналаштований компонент стає коренем додатку, якщо ніяких маршрутів не 
//визначено.

const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);

React

} // кінець класу TodoList

// Компонент TodoList включається
// в зазначений DOM-елемент.
// Якщо TodoList використовувався не в одному місті,
// ця частина коду буде перенесена у інший JavaScript-файл.
ReactDOM.render(
  <todolist>,
  document.getElementById('container'));

Синтаксис Шаблону

Angular 2

// Це значення властивостей шаблону @Component.
  // Воно було поміщене сюди для того, аби
  // можна було легко порівняти з React-методами.
  `<div>
    <h2>To Do List</h2>
    <div>
      {{uncompletedCount}} of
      {{state.todos.length}} remaining
      
      <button (click)="onArchiveCompleted()">
        Archive Completed
      </button>
    </div>
    <br>
    <form>
      
      
      <input (input)="onChange($event.target.value)" [ng-model]="state.todoText" autofocus="" placeholder="enter new todo here" size="30" type="text">
      <button (click)="onAddTodo()" [disabled]="!state.todoText">
        Add
      </button>
    </form>
    <ul>
      
      <todo (on-delete-todo)="onDeleteTodo($event)" (on-toggle-done)="onToggleDone($event)" *ngfor="let todo of state.todos" [todo]="todo"></todo>
    </ul>
  </div>

React

render() {
    // Можна присвоїти частину згенерованого UI
    // змінній і звернутися до неї пізніше.
    const todos = this.state.todos.map(todo =>
      <todo key="{todo.id}" ondeletetodo="{this.onDeleteTodo.bind(this," ontoggledone="{this.onToggleDone.bind(this," todo="{todo}" todo)}="" todo.id)}="">);

    return (
      <div>
        <h2>To Do List</h2>
        <div>
          {this.uncompletedCount} of
          {this.state.todos.length} remaining
          <button =="" onclick="{()"> this.onArchiveCompleted()}>
            Archive Completed
          </button>
        </div>
        <br>
        <form>
          <input =="" autofocus="" onchange="{e" placeholder="enter new todo here" size="30" type="text" value="{this.state.todoText}"> this.onChange('todoText', e)}/>
          <button =="" disabled="{!this.state.todoText}" onclick="{()"> this.onAddTodo()}>
            Add
          </button>
        </form>
        <ul classname="unstyled">{todos}</ul>
      </div>
    );
 }

Код компонента для Angular 2, як правило, більш багатослівний, ніж для React. Єдиний випадок, де React вимагає більше коду – це з самоналаштуванням. Цю невідповідність можна віднести до TypeScript. :void ,:ITodo і інших типів, що часто зустрічаються у TypeScript. Стиль Angular 2 зазвичай вимагає, щоб змінні, параметри функції і самі функції мали тип в TypeScript. React не має нічого подібного, і це робить код більш зручним для розробників, які віддають перевагу традиційному JavaScript.

Angular 2 використовує @Component декоратори для визначення різних конструкцій (сервіси, директиви, пайпи), які він містить у собі, та визначення своїх власних властивостей. Він також дозволяє розробнику вказати selectorдля компонента і помістити код для шаблону за допомогою властивості template або templateUrl, якщо окремий файл використовується. Те ж саме відноситься і до стилів - є можливість для введення стилів безпосередньо за допомогою властивості stylesабо при використанні безлічі файлів за допомогою styleUrls. React не має аналога для компонента декоратора і вимагає шаблон компонента для включення в сам файл компонента, тим самим обмежуючи варіанти для налаштування, тому інформація про компонент стає важчою для інтерпретування.

Angular 2 шаблони поставляються з конкретним погодженням для різних елементів:

  • * означає директиву, яка маніпулює DOM. Наприклад, *ngFor перебирає масив значень і створює новий елемент для кожного з них. *ngIf використовується для позначення того, чи елемент можна побачити, чи ні.
  • [] демонструє властивість зв'язування, що вказує, чи елемент приймає значення від компонента. Він використовується в основному для передачі даних дочірнього компонента до батька чи матері.
  • () вказує на подію зв'язування (наприклад, (click), який викликає функцію в компонентах).
  • [()] вказує на двостороннє зв'язування, а це означає, що будь-які зміни в даних, які передаються, будуть поширюватися.

React шаблони показуються з їх особливостями. JSX розмиває зв'язок між HTML і JavaScript, надаючи свою власну розмітку. Навіть якщо здається, що шаблон записується в HTML, насправді діє розмітка XML, яка пізніше перетворюється в HTML. Через JSX, стандартні слова HTML є camel-cased або мають різні імена - onclickв JSX - OnClick. for(використовується в мітках) стає htmlFor, тому що forє зарезервованим словом в JavaScript.

Вкладені компоненти

Далі, давайте подивимося, як в компонент для одного елемента ToDo виглядає як в Angular 2, так і в React:

Angular 2

import {Component, Input, Output, EventEmitter}
  from 'angular2/angular2';

export interface ITodo {
  id: number;
  text: string;
  done: boolean;
}

@Component({
  selector: 'todo',
  template: `
    <li>
      <input (change)="toggleDone()" [checked]="todo.done" type="checkbox">
      <span [ng-class]="'done-' + todo.done">
        {{todo.text}}
      </span>
      <button (click)="deleteTodo()">Delete</button>
    </li>`
})
export class TodoCmp {
  // @Input дозволяє отримати
  // ініціалізовану змінну з певного конпонента.
  @Input() todo: ITodo;
  // @Output дозвонялє друкувати
  // змінну з певного компонента.
  @Output() onDeleteTodo:
    EventEmitter<number> = new EventEmitter<number>();
  @Output() onToggleDone:
    EventEmitter<itodo> = new EventEmitter<itodo>();

  deleteTodo(): void {
    this.onDeleteTodo.next(this.todo.id);
  }

  toggleDone(): void {
    this.onToggleDone.next(this.todo);
  }
}

React

import React from 'react';

// Є три варіанти, щоб означити React компоненти.
// Це функціональний компонент без стану з
// якого можна лише отримати дані через "реквізити".
// Реквізити об'єкту передаються цій функції
// і видаляються.
const Todo = ({onDeleteTodo, onToggleDone, todo}) =>
  <li>
    <input checked="{todo.done}" onchange="{onToggleDone}/" type="checkbox">
    <span +="" classname="{'done-'" todo.done}="">
      {todo.text}
    </span>
    <button onclick="{onDeleteTodo}">Delete</button>
  </li>;

// Додаткове підтвердження реквізиту об'єкта.
const PropTypes = React.PropTypes;
Todo.propTypes = {
  todo: PropTypes.object.isRequired,
  onDeleteTodo: PropTypes.func.isRequired,
  onToggleDone: PropTypes.func.isRequired
};

export default Todo;

Через те, що це основний блок React додатка, то компонент забезпечує більшу гнучкість в тому, як застосування може бути структуроване. Компоненти без стану побудовані з односпрямованим потоком даних в пам'яті, залишаючи більшу частину логіки за межами самого компонента. Angular 2 також пропонує аналогічні функціональні можливості, але з більшою складністю.

Архітектура додатку

Angular 2

Двонаправлений поток даних типовий для моделей MVC {full-post-img}

Angular 2 використовує стандартну двосторонню модель потоку даних. Після того, як дія проводиться, дані йдуть до рівня обслуговування, далі йдуть назад на огляд. Цей спосіб маніпулювання даними піддався широкій критиці, оскільки стан даних може бути змінений в обох напрямках, що призводить до неузгодженості.

React

Потік даних Flux {full-post-img}

eact використовує Flux для побудови своїх додатків. Кожна дія передається диспетчеру, який посилає нову інформацію на склад. На складах інформація оновлюється (мутується) і відправляється назад на огляд, де відбуваються зміни.

Redux

Потік даних Redux

Redux, як і Flux, заснований на односпрямованому потоці даних, але він управляє даними по-іншому.

Додаток, який використовує Redux має глобальний стан, який є загальним для всієї програми. Коли дія зроблена, вона надсилається диспетчеру, який служить для виконання HTTP-викликів до API. Потім зміни направляються редукторам - чистим функціям, які спеціалізуються на управлінні частиною глобального стану програми. Наприклад, якщо ваш додаток має користувачів, проекти і елементи в якості моделей, кожна з моделей буде частиною глобального стану і буде набір перехідників, які беруть на себе управління їх станом. Після того як стан «мутували» редукторами, нова інформація спрямовується вниз на огляд.

Таким чином, стан додатку зберігається в одному місці, що забезпечує більш легке управління станами.

Redux був вперше введений для React в якості альтернативи, щоб спростити Flux. Через це, Redux набув більш широкого поширення в React.

Останнім часом Angular 2 почав приймати шаблон Redux для потоку даних шляхом використання rxjs для підтримки стану даних, використовуючи чисті функцій, щоб маніпулювати станами. Були зроблені спроби для створення односпрямованого потоку даних в Angular 2 додатках, але питання прийняття цього методу все ще залишається вікритим.

Продуктивність

Продуктивність є ще однією критичною точкою порівняння. Вона показує, як Angular 2 і React обробляються при великому навантаженні і дає передбачення для майбутніх проблем, так як чим об'ємнішими стають додатки, тим складніше їх оптимізувати.

Випробування проводяться з Selenium для емітації дій користувача і запису результатів (в мілісекундах).

React vs. Angular 2

І Angular 2, і React стоять, здається, на одному рівні. Angular 2 має невелику перевагу на всіх DOM маніпуляціях для створення нових елементів.

З точки зору управління пам'яттю, React обганяє Angular 2 з використанням меншого обсягу пам'яті, особливо після завантаження сторінки. Це відбувається, головним чином через те, що сам по собі React меншого розміру, ніж Angular 2.

Кросс-платформенна інтеграція

Світ крос-платформенної розробки зробив величезний стрибок через масове прийняття мобільних пристроїв. Тепер, WebView-інструменти для побудови крос-платформенних мобільних додатків є застарілими.

Є два інструменти, які дозволяють будувати крос-платформні додатки для Angular 2 і React, відповідно - NativeScript і React Native. NativeScript, побудований за допомогою Telerik (нині Progress), призначений для того, щоб мобільні додатки могли бути побудовані за допомогою Angular 2. Навіть якщо у нього є тільки 8k зірочок на Github, NativeScript є зрілим і поставляється з великою документацією і численними розширеннями. Він проповідує "напиши один раз, запускай скрізь" методологію розробки крос-платформенних додатків. Навіть при тому, що це ефективний підхід, він не дозволяє розробникам використовувати багато специфічних можливостей для користувацького інтерфейсу.

З іншого боку, React Native, розроблений Facebook, дає React власні можливості. У порівнянні з NativeScript, React Native все ще молодий, але досить популярний і швидко росте, із 37K зірками на GitHub. React Native використовує "навчися один раз, пиши в будь-якому місці" підхід до розробки крос-платформенних додатків. Замість того щоб намагатися узагальнити різні платформи, як це робить NativeScript, React Native охоплює свої розбіжності, пропонуючи різні способи побудови призначеного для користувача інтерфейсу для різних платформ. Останнім часом команда Angular 2 приступила до прийняття React Native, роблячи візуалізатор для нього.

Вибір

Angular 2 має трохи більше 18k зірок на Github. Є ~ 15 000 репо на Github, які містять «Angular 2» або «ng2» і написані на TypeScript.

React, з іншого боку, має більше 53K зірок на Github. Є 95 500 репо, що містять слово «react», це приблизно у дев'ять разів більше, ніж має Angular 2.

Проте, одна з головних причин для великого числа репо є те, що React поставляється з кількома вбудованими функціональними можливостями і від його користувачів залежить забезпечення необхідним оснащенням для розробки повноцінних додатків.

Заключення

І Angular 2, і React розвивають великі корпорації і обидва інструмента можуть похвалитися гарною підтримкою. Незважаючи на те, що вони мають різну філософію до того, який повинен бути підхід до розробки додатків, для них обох є місце у світі розробки програмного забезпечення.

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 5.8K
Приєднався: 8 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація