Автор статьи, первую часть перевода которой мы публикуем, говорит, что он уже около двух лет работает над крупномасштабным Angular-приложением в Trade Me. В течение последних нескольких лет команда разработчиков приложения постоянно занимается совершенствованием проекта — как в плане качества кода, так и в том, что касается производительности.


В этой серии материалов речь пойдёт о подходах к разработке, используемые командой Trade Me, которые выражены в виде более чем двух десятков рекомендаций, касающихся таких технологий, как Angular, TypeScript, RxJS и @ngrx/store. Кроме того, определённое внимание здесь будет уделено универсальным техникам программирования, которые направлены на то, чтобы сделать код приложений чище и аккуратнее.

1. О trackBy


Применяя ngFor для обхода массивов в шаблонах, используйте эту конструкцию с функцией trackBy, которая возвращает уникальный идентификатор для каждого элемента.

?Пояснения


Когда массив изменяется, Angular выполняет повторный рендеринг всего дерева DOM. Но если вы используете trackBy, система будет знать о том, какой элемент изменился и внесёт в DOM изменения, касающиеся только этого конкретного элемента. Подробности об этом можно почитать здесь.

?До


<li *ngFor="let item of items;">{{ item }}</li>

?После


// в шаблоне
<li *ngFor="let item of items; trackBy: trackByFn">{{ item }}</li>
// в компоненте
trackByFn(index, item) {    
   return item.id; // уникальный id, соответствующий элементу
}

2. Ключевые слова const и let


Если вы собираетесь объявить переменную, значение которой менять не планируется — используйте ключевое слово const.

?Пояснения


Уместное использование ключевых слов let и const проясняет намерение, касающееся применения объявленных с их помощью сущностей. Кроме того, такой подход облегчает распознавание проблем, вызванных случайной перезаписью значений констант. В такой ситуации выдаётся ошибка компиляции. Кроме того, это улучшает читабельность кода.

?До


let car = 'ludicrous car';
let myCar = `My ${car}`;
let yourCar = `Your ${car};
if (iHaveMoreThanOneCar) {
   myCar = `${myCar}s`;
}
if (youHaveMoreThanOneCar) {
   yourCar = `${youCar}s`;
}

?После


// значение car не перезаписывается, поэтому мы можем сделать car константой
const car = 'ludicrous car';
let myCar = `My ${car}`;
let yourCar = `Your ${car};
if (iHaveMoreThanOneCar) {
   myCar = `${myCar}s`;
}
if (youHaveMoreThanOneCar) {
   yourCar = `${youCar}s`;
}

3. Конвейеризуемые операторы


При работе с RxJS используйте конвейризуемые операторы.

?Пояснения


Конвейеризуемые операторы поддерживают алгоритм tree-shake, то есть — при их импорте в проект будет включён лишь код, который планируется выполнять. Это, кроме того, упрощает идентификацию неиспользуемых операторов в файлах.

Обратите внимание на то, что эта рекомендация актуальна для Angular версии 5.5 и выше.

?До


import 'rxjs/add/operator/map';
import 'rxjs/add/operator/take';
iAmAnObservable
    .map(value => value.item)
    .take(1);

?После


import { map, take } from 'rxjs/operators';
iAmAnObservable
    .pipe(
       map(value => value.item),
       take(1)
     );

4. Изоляция исправлений API


Не все API совершенно стабильны и лишены ошибок. Поэтому иногда требуется вводить в код некую логику, направленную на исправление проблем API. Вместо того чтобы размещать эту логику в компонентах, где используются исправляемые API, лучше будет где-то её изолировать, например — в сервисе, и обращаться из компонента уже не к проблемному API, а к соответствующему сервису.

?Пояснения


Предложенный подход позволяет держать исправления «ближе» к API, то есть, настолько близко к тому коду, из которого выполняются сетевые запросы, насколько это возможно. В результате уменьшается объём кода приложения, взаимодействующего с проблемными API. Кроме того, так оказывается, что все исправления находятся в одном месте, в результате с ними легче будет работать. Если вам приходится исправлять ошибки в API, то гораздо проще делать это в каком-то одном файле, чем разбрасывать эти исправления по всему приложению. Это облегчает не только создание исправлений, но и поиск соответствующего кода в проекте, и его поддержку.

Кроме того, можно создавать собственные теги, наподобие API_FIX (что напоминает тег TODO), и помечать ими исправления. Это упрощает поиск таких исправлений.

5. Подписка в шаблоне


Избегайте подписки на наблюдаемые объекты (observables) из компонентов. Вместо этого оформляйте подписки на них в шаблонах.

?Пояснения


Асинхронные конвейеризуемые операторы автоматически отписывают сами себя, что упрощает код, исключая необходимость в ручном управлении подписками. Это, кроме того, уменьшает риск того, что разработчик забудет отписаться от подписки в компоненте, что может привести к утечкам памяти. Снизить вероятность возникновения утечек памяти можно и с использованием правил линтера, направленных на выявление наблюдаемых объектов, от которых не отписались.

Кроме того, применение такого подхода приводит к тому, что компоненты перестают быть компонентами с состоянием, что может приводить к ошибкам когда данные меняются вне подписки.

?До


// шаблон
<p>{{ textToDisplay }}</p>
// компонент
iAmAnObservable
    .pipe(
       map(value => value.item),
       takeUntil(this._destroyed$)
     )
    .subscribe(item => this.textToDisplay = item);

?После


// шаблон
<p>{{ textToDisplay$ | async }}</p>
// компонент
this.textToDisplay$ = iAmAnObservable
    .pipe(
       map(value => value.item)
     );

6. Удаление подписок


Подписываясь на наблюдаемые объекты всегда следите за тем, чтобы подписки на них правильно удалялись, используя операторы наподобие take, takeUntil и так далее.

?Пояснения


Если не отписаться от наблюдаемого объекта — это приведёт к утечкам памяти, так как поток наблюдаемого объекта останется открытым, что возможно даже после разрушения компонента или после того, как пользователь перейдёт на другую страницу приложения.

Ещё лучше будет создать правило линтера для обнаружения наблюдаемых объектов с действующей подпиской на них.

?До


iAmAnObservable
    .pipe(
       map(value => value.item)     
     )
    .subscribe(item => this.textToDisplay = item);

?После


Воспользуйтесь оператором takeUntil в том случае, если вы хотите наблюдать за изменениями какого-то объекта до тех пор, пока другой наблюдаемый объект не сгенерирует некое значение:

private destroyed$ = new Subject();
public ngOnInit (): void {
    iAmAnObservable
    .pipe(
       map(value => value.item)
      // Мы хотим прослушивать iAmAnObservable до разрушения компонента
       takeUntil(this._destroyed$)
     )
    .subscribe(item => this.textToDisplay = item);
}
public ngOnDestroy (): void {
    this._destroyed$.next();
}

Использование чего-то наподобие this — это паттерн, применяемый для управления удалением подписок на множество наблюдаемых объектов в компоненте.

Используйте take если вам нужно лишь первое значение, выдаваемое наблюдаемым объектом:

iAmAnObservable
    .pipe(
       map(value => value.item),
       take(1),
       takeUntil(this._destroyed$)
    )
    .subscribe(item => this.textToDisplay = item);

Обратите внимание на то, что здесь мы используем takeUntil с take. Это делается для того, чтобы избежать утечек памяти, вызванных тем, что подписка не привела к получению значения до разрушения компонента. Если бы здесь не использовалась функция takeUntil, подписка существовала бы до получения первого значения, но так как компонент был бы уже уничтожен, это значение никогда не было бы получено, что привело бы к утечке памяти.

7. Использование подходящих операторов


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

  • Используйте switchMap когда вам нужно игнорировать предыдущее диспетчеризованное действие при поступлении нового действия.
  • Используйте mergeMap в том случае, если нужно параллельно обрабатывать все диспетчеризованные действия.
  • Используйте concatMap тогда, когда действия нужно обрабатывать одно за другим, в порядке их поступления.
  • Используйте exhaustMap в ситуациях, когда, в процессе обработки ранее поступивших действий, вам нужно игнорировать новые.

Подробности об этом можно почитать здесь.

?Пояснения


Использование, если есть такая возможность, одного оператора, вместо того, чтобы достигать того же эффекта за счёт объединения в цепочку нескольких операторов, приводит к сокращению объёма кода приложения, который нужно отправить пользователю. Использование неудачно выбранного оператора может привести к неправильному поведению программы, так как разные операторы по-разному обрабатывают наблюдаемые объекты.

8. Ленивая загрузка


Тогда, когда это возможно, попытайтесь организовать ленивую загрузку модулей Angular-приложения. Данная техника сводится к тому, что нечто загружается только в том случае, если оно используется. Например — компонент загружается только тогда, когда его нужно вывести на экран.

?Пояснения


Ленивая загрузка уменьшает размер материалов приложения, которые приходится загружать пользователю. Это может улучшить скорость загрузки приложения за счёт того, что неиспользуемые модули не передаются с сервера клиентам.

?До


// app.routing.ts
{ path: 'not-lazy-loaded', component: NotLazyLoadedComponent }

?После


// app.routing.ts
{ 
  path: 'lazy-load',
  loadChildren: 'lazy-load.module#LazyLoadModule' 
}
// lazy-load.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { LazyLoadComponent }   from './lazy-load.component';
@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild([
         { 
             path: '',
             component: LazyLoadComponent 
         }
    ])
  ],
  declarations: [
    LazyLoadComponent
  ]
})
export class LazyModule {}

9. О подписках внутри других подписок


Иногда вам, для выполнения некоего действия, могут понадобиться данные из нескольких наблюдаемых объектов. В подобной ситуации избегайте создания подписок на такие объекты внутри блоков subscribe других наблюдаемых объектов. Вместо этого применяйте подходящие операторы для объединения команд в цепочки. Среди таких операторов можно отметить withLatestFrom и combineLatest. Рассмотрим примеры, после чего прокомментируем их.

?До


firstObservable$.pipe(
   take(1)
)
.subscribe(firstValue => {
    secondObservable$.pipe(
        take(1)
    )
    .subscribe(secondValue => {
        console.log(`Combined values are: ${firstValue} & ${secondValue}`);
    });
});

?После


firstObservable$.pipe(
    withLatestFrom(secondObservable$),
    first()
)
.subscribe(([firstValue, secondValue]) => {
    console.log(`Combined values are: ${firstValue} & ${secondValue}`);
});

?Пояснения


Если говорить о читабельности, о сложности кода, или о признаках плохого кода, то, когда в программе возможности RxJS в полной мере не используются, это говорит о том, что разработчик недостаточно хорошо знаком с API RxJS. Если затронуть тему производительности, то окажется, что если наблюдаемому объекту нужно некоторое время на инициализацию, то будет осуществлена подписка на firstObservable, потом система будет ждать завершения операции, и только после этого начнётся работа со вторым наблюдаемым объектом. Если эти объекты представляют собой сетевые запросы, то выглядеть это будет как синхронное выполнение запросов.

10. О типизации


Всегда старайтесь объявлять переменные или константы с типом, отличающимся от any.

?Пояснения


При объявлении в TypeScript переменной или константы без указания типа тип будет выведен на основании назначаемого ей значения. Это может привести к проблемам. Рассмотрим классический пример поведения системы в подобной ситуации:

const x = 1;
const y = 'a';
const z = x + y;
console.log(`Value of z is: ${z}`
// Вывод
Value of z is 1a

Предполагается, что y здесь является числом, но наша программа об этом не знает, поэтому она выводит нечто такое, что выглядит неправильно, но никаких сообщений об ошибках не выдаёт. Подобных проблем можно избежать, назначая переменным и константам подходящие типы.

Перепишем вышеприведённый пример:

const x: number = 1;
const y: number = 'a';
const z: number = x + y;
// Тут появится ошибка компиляции:
Type '"a"' is not assignable to type 'number'.
const y:number

Это помогает избежать ошибок, связанных с типами данных.

Ещё одно преимущество систематического подхода к типизации заключается в том, что это упрощает рефакторинг и снижает вероятность ошибок в ходе этого процесса.

Рассмотрим пример:

public ngOnInit (): void {
    let myFlashObject = {
        name: 'My cool name',
        age: 'My cool age',
        loc: 'My cool location'
    }
    this.processObject(myFlashObject);
}
public processObject(myObject: any): void {
    console.log(`Name: ${myObject.name}`);
    console.log(`Age: ${myObject.age}`);
    console.log(`Location: ${myObject.loc}`);
}
// Вывод
Name: My cool name
Age: My cool age
Location: My cool location

Предположим, что мы хотели поменять, в объекте myFlashObject, имя свойства loc на location и допустили ошибку в ходе редактирования кода:

public ngOnInit (): void {
    let myFlashObject = {
        name: 'My cool name',
        age: 'My cool age',
        location: 'My cool location'
    }
    this.processObject(myFlashObject);
}
public processObject(myObject: any): void {
    console.log(`Name: ${myObject.name}`);
    console.log(`Age: ${myObject.age}`);
    console.log(`Location: ${myObject.loc}`);
}
// Вывод
Name: My cool name
Age: My cool age
Location: undefined

Если при создании объекта myFlashObject не используется типизация, то в нашем случае система полагает, что значением свойства loc объекта myFlashObject является undefined. Она не задумывается о том, что loc может представлять собой недопустимое имя свойства.

Если при описании объекта myFlashObject применяется типизация, то в подобной ситуации мы увидим, при компиляции кода, замечательное сообщение об ошибке:

type FlashObject = {
    name: string,
    age: string,
    location: string
}
public ngOnInit (): void {
    let myFlashObject: FlashObject = {
        name: 'My cool name',
        age: 'My cool age',
        // Ошибка компиляции
        Type '{ name: string; age: string; loc: string; }' is not assignable to type 'FlashObjectType'.
        Object literal may only specify known properties, and 'loc' does not exist in type 'FlashObjectType'.
        loc: 'My cool location'
    }
    this.processObject(myFlashObject);
}
public processObject(myObject: FlashObject): void {
    console.log(`Name: ${myObject.name}`);
    console.log(`Age: ${myObject.age}`)
    // Ошибка компиляции
    Property 'loc' does not exist on type 'FlashObjectType'.
    console.log(`Location: ${myObject.loc}`);
}

Если вы начинаете работу над новым проектом, полезно будет задать, в файле tsconfig.json, опцию strict:true для того, чтобы включить строгую проверку типов.

11. Об использовании линтера


У tslint имеются различные стандартные правила наподобие no-any, no-magic-numbers, no-console. Линтер можно настраивать, редактируя файл tslint.json для того, чтобы организовать проверку кода по определённым правилам.

?Пояснения


Использование линтера для проверки кода означает, что, если в коде встречается что-то такое, что запрещено правилами, вы получите сообщение об ошибке. Это способствует единообразию кода проекта, улучшает его читабельность. Здесь можно ознакомиться с другими правилами tslint.

Надо отметить, что некоторые правила включают в себя и средства исправления того, что в соответствии с ними считается недопустимым. При необходимости можно создавать собственные правила. Если вам это интересно — взгляните на данный материал, в котором идёт речь о создании собственных правил для линтера с использованием TSQuery.

?До


public ngOnInit (): void {
    console.log('I am a naughty console log message');
    console.warn('I am a naughty console warning message');
    console.error('I am a naughty console error message');
}
// Вывод. Никаких сообщений об ошибках, в консоль выводится следующее:
I am a naughty console message
I am a naughty console warning message
I am a naughty console error message

?После


// tslint.json
{
    "rules": {
        .......
        "no-console": [
             true,
             "log",    // команда console.log запрещена
             "warn"    // команда console.warn запрещена
        ]
   }
}
// ..component.ts
public ngOnInit (): void {
    console.log('I am a naughty console log message');
    console.warn('I am a naughty console warning message');
    console.error('I am a naughty console error message');
}
// Вывод. Линтер выводит ошибки для команд console.log and console.warn и не сообщает об ошибках применительно к console.error, так как эта команда не упомянута в настройках
Calls to 'console.log' are not allowed.
Calls to 'console.warn' are not allowed.

Итоги


Сегодня мы рассмотрели 11 рекомендаций, которые, надеемся, пригодятся Angular-разработчикам. В следующий раз ждите ещё 11 советов.

Уважаемые читатели! Пользуетесь ли вы фреймворком Angular для разработки веб-проектов?

Комментарии (22)


  1. Zet_Roy
    09.10.2018 13:11
    -2

    Совет номер 1 не использовать Angular…


    1. s1im
      09.10.2018 13:32
      +1

      Зачем писать такое в статьях посвященных тем, кому данный фреймворк интересен? Есть ли у вас аргументы, обосновывающий сей ценный совет?


      1. miraage
        09.10.2018 14:09

        Я бы не ждал аргументов после предыдущей реплики.


      1. anfield343
        09.10.2018 15:37

        это коммент скорее из разряда, абы ляпнуть, ну или шутка такая)


      1. Zet_Roy
        09.10.2018 20:11

        Angular уже давно как неактуальный а использовать его это головная боль для разработчика.


        1. babylon
          10.10.2018 07:09

          удален


      1. vintage
        09.10.2018 23:51
        +1

        1. Zet_Roy
          10.10.2018 01:14

          Коммент в тему.
          Я когда пытался сделать по ангуляру тестовое то возникали различного рода странности и ошибки где рендер 3 элементов вызывался 9 раз вместо 3, или когда контекст элемента не передается в другой контролер и его нужно было передавать окольными путями создавая спагетти код и многое другое, после некоторых попыток я все это дело забросил и нашел вакансию по React с которым у меня не возникало таких неразрешимых проблем.


          1. VitaLik_is_goodman
            10.10.2018 02:00

            Комментарий из разряда, не понимаю, но критикую. А плохо только одно, что вы не разобрались. C react свои проблемы, при всей простоте самой react.js экосистема вокруг него это ужас, каждый проект — это сборная солянка по архитектурным решениям и используемым библиотекам, только state manager: redux, mobx, mobx-state-tree, aync: redux-thunk, redux-saga, rxjs, не говоря уже о том что доки по webpack надо будет курить постоянно, и кривая входа растет дальше больше, тогда как с angular на начальном этапе сложно, а потом проще и в проект вливаться значительно проще


            1. Zet_Roy
              10.10.2018 13:28

              На React я всегда знаю что происходит так как он прост но очень функционален.

              экосистема вокруг него это ужас

              Экосистема очень помогает в разработке сложных интерфейсов и ко всем им есть документация

              state manager: redux, mobx, mobx-state-tree, aync: redux-thunk, redux-saga, rxjs

              Если разобраться там нет ничего сложного.

              доки по webpack надо будет курить постоянно

              Ну так не используй webpack, в чем проблема?

              тогда как с angular на начальном этапе сложно, а потом проще и в проект вливаться значительно проще

              В angular всегда сложно и не понимаешь почему рендерится оно по 16 раз вместо 1, почему контекст не передается, почему возникают непонятные ошибки и многое другое.


              1. guleaevvlad
                10.10.2018 21:53

                Мне например все понятно из того что ты перечислил


              1. VitaLik_is_goodman
                11.10.2018 01:42

                Ну так не используй webpack, в чем проблема?

                ну, честно, вы как не работали ровно с React. Что значит не использовать webpack? его надо постоянно тюнить, то нужно билд разбить и динамически подгружать по роуту, то нужно SSR подключить, и нужно постоянно что-то дописывать на каждый чих, даже в готовые шаблоны проектов, потому что нет универстального одного

                Если разобраться там нет ничего сложного.

                Если разобраться, то и с brainfuck все отлично, но это ненормально, когда на одном проекте react+redux+thunk+router3, на другом react+redux+saga+router4+recompose и все компоненты functional, еще видел проект, где была ramda c flow, где-то typescript. Что это, почему каждый проект — это как новая вселенная со своими архитектурными решениями?

                Экосистема очень помогает в разработке сложных интерфейсов и ко всем им есть документация

                Ну видимо формы и таблицы не относятся к сложным интерфейсам

                почему контекст не передается, почему возникают непонятные ошибки и многое другое

                Какой контекст не передается, какой контролер, вы о чем? Речь в статье идет про angular 2+!


                1. Zet_Roy
                  11.10.2018 19:41

                  ну, честно, вы как не работали ровно с React. Что значит не использовать webpack? его надо постоянно тюнить, то нужно билд разбить и динамически подгружать по роуту, то нужно SSR подключить, и нужно постоянно что-то дописывать на каждый чих, даже в готовые шаблоны проектов, потому что нет универстального одного

                  Нормально я работал без webpack делал проекты и не жаловался. Webpack не нужен, это еще одна ненужна приблуда наравне с ангуляром.

                  Если разобраться, то и с brainfuck все отлично, но это ненормально, когда на одном проекте react+redux+thunk+router3, на другом react+redux+saga+router4+recompose и все компоненты functional, еще видел проект, где была ramda c flow, где-то typescript. Что это, почему каждый проект — это как новая вселенная со своими архитектурными решениями?

                  Ну так это удобно есть модули которые нужны их и загружаешь в зависимости от проекта. Архитектурные решения разные в зависимости от того что нужно сделать.

                  Какой контекст не передается, какой контролер, вы о чем? Речь в статье идет про angular 2+!

                  А ну значит ты не работал с ангуляром.


            1. nsinreal
              11.10.2018 00:51

              Ой, я тут мимо проходил и решил написать. Я в корне не согласен, мой опыт использования angular говорит о обратном. На начальном этапе с angular все очень просто. Можно начинать писать вообще мало чего зная. С каждым месяцем использования Angular я находил новые интересные особенности, которые приводили меня в бешенство. По итогу общего опыта работы в полтора года с этим чудом я не возьму ангуляр для проекта длинее месяца и сложнее говноформочек.

              Дальше, вы весьма неправы касательно state manager. Начнем с того, что в самом Angular уже идёт два механизма отслеживания изменений из коробки: либо на каждый чих, либо OnPush. Первый идеально подходит для случаев, когда не нужно управлять стейтом. Второй является основой для стейт менеджмента, при этом не самого лучшего качества. И да, вы можете подключить redux, ngrx (похоже на redux, но несовместимо с redux), mobx и я не знаю что ещё. Другое дело, что для многих проектов эти вещи не нужны.

              Особенных лулзов я ловлю с того, что вы включили в свой список rxjs. По моим ощущением, за пределами Angular он мало кому сдался по объективным причинам.


              1. VitaLik_is_goodman
                11.10.2018 01:54

                По итогу общего опыта работы в полтора года с этим чудом я не возьму ангуляр для проекта длинее месяца и сложнее говноформочек.

                Если у вас не хватает экспертизы, это не значит, что инструмент плохой. Skyeng и tinkoff активно используют и ничего, все работает

                Дальше, вы весьма неправы касательно state manager

                А в чем не прав? Мой аргумент был, что в экосистеме react state manager обязателен и посколько facebook не озаботился все размыто (flux, reflux, refux и тд) и так со всеми библиотеками, причем тут ChangeDetectionStrategy, которые по сути аналогичны Component и PureComponent

                Особенных лулзов я ловлю с того, что вы включили в свой список rxjs.

                Ок, redux, ramda, flow, immutable.js за пределами React.js «мало кому сдался по объективным причинам». Но я не ловлю с этого лулзов, потому что это нормально, инструмент обычно нужен для определенных целей


                1. nsinreal
                  11.10.2018 14:56

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

                  Skyeng и tinkoff активно используют и ничего, все работает
                  Это какой-то извращенный вариант демагогического аргумента про авторитеты? Или это ошибка репрезентативности, когда вы не в курсе про проблемы отдельных разработчиков?

                  Мой аргумент был, что в экосистеме react state manager обязателен и посколько facebook не озаботился все размыто (flux, reflux, refux и тд) и так со всеми библиотеками
                  Да, вы правы, когда говорите, что для react использование state manager скорее обязательно (хотя на самом деле нет). Но когда вы будете пилить сложное приложение на angular, то вам придется подключать state manager.
                  Между тем, я не считаю это серьезной проблемой, потому что сейчас нельзя заставить все веб-приложения работать только через один подход.

                  А неправы вот вы в чем: в вашем оригинальном сообщении был наезд на React за то, что проекты на React используют разные решения для управления стейтом. Но проекты на Angular тоже используют разные решения для управления стейтом!

                  ChangeDetectionStrategy, которые по сути аналогичны Component и PureComponent
                  Вообще не правильно.
                  При ChangeDetectionStrategy.Default у вас компонент перерисовывается на каждое событие, в том числе и на каждый mousemove. У реакта такого чуда нет.
                  При ChangeDetectionStrategy.OnPush ваш компонент начинает работать чем-то похоже на React.PureComponent

                  Ок, redux, ramda, flow, immutable.js за пределами React.js «мало кому сдался по объективным причинам». Но я не ловлю с этого лулзов, потому что это нормально, инструмент обычно нужен для определенных целей

                  Драма в том, что redux, ramda, flow, immutable.js не являются обязательным для работы с react. А вот rxjs является обязательным для работы с Angular, потому что Angular очень многое делает через него. Но это не более чем забавный момент.


    1. psFitz
      09.10.2018 15:19

      Зря зря зря


  1. myemuk
    09.10.2018 15:37

    Почти все уже знал, но не все. Век живи — век учись. Добавил в закладки.


  1. Golem765
    09.10.2018 18:06

    Не могу согласиться с советом про trackBy, конечно знать его нужно и есть случаи когда без него не обойтись, но использовать его везде кажется излишним


  1. Vahman
    09.10.2018 19:43

    Там в комментариях к оригинальной статье, было ценное уточнение про async pipe. Не очень удобно часто писать | async, плюс можно наплодить подписчиков. Есть небольшой обход. Например один observable надо прокинуть в несколько дочерних компонент


    <div>
      <child-one
        [data]="(data$ | async)?.propOne">
      </child-one>
      <child-two
        [data]="(data$ | async)?.propTwo">
      </child-two>
    </div>

    Получается не очень красиво. Можно сделать так:


    <div *ngIf="data$ | async as data>
      <child-one
        [data]="data.propOne">
      </child-one>
      <child-two
        [data]="data.propTwo">
      </child-two>
    </div>

    А в целом отличная и полезная статья


  1. Vahman
    09.10.2018 19:56

    В ответ на вопрос в конце статьи — да, используем в проде, очень плотно. Раньше был angularJS и React. На данный момент все новые разработки перевели на Angular, полет нормальный, напилена база компонент, которая используется во множестве наших проектов.
    PS. странно что в статье не написали ничего по ChangeDetectionStrategy, можно получить неплохой прирост производительности


  1. bluetooth
    10.10.2018 17:36

    Многие советы относятся скорее к TS, чем к Angular. С таким же успехом можно наскрести 20 советов по TS и выдать их за советы по Angular…