Это часть 1 из текущей серии статей. Также доступна Часть 2 с более продвинутыми концепциями.

Я впал в аналитический паралич, когда написал в Basware сообщение в блоге «все в одном» об использовании MobX на Angular (2+), но в итоге я его прочитал довольно тяжело. Вместо этого я делаю серию более коротких, надеюсь, более сложных постов. (Рассказчик: в итоге получилось не коротко и не сложно)

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

Магазин

MobX на самом деле не строится вокруг «магазинов». Вы можете распределить свое состояние по своему усмотрению (например, десятки различных сервисов Angular или классов ES6, если вам так хочется). Простое состояние всегда легче отследить, но нет необходимости возить культ единого Бога-объекта, чтобы вместить все. Механика MobX будет работать независимо от того, как вы разделите свое состояние.

Наблюдаемые

Вероятно, есть небольшое подмножество состояний, которое действительно нужно изменить. Они отмечены декоратором @observable и обычно представляют собой примитивы, массивы, объекты и карты ES6. Обратите внимание, что лучше или хуже, вы должны использовать ES6 Maps вместо объектов для представления словарей (поскольку MobX не может обнаруживать ключи, добавляемые к объектам). «Изменение состояния» означает запись в эти поля (изменение, переназначение и т. Д.).

Расчетные свойства

@computed декоратор отмечает средство получения свойства ES6, которое использует некоторые из наблюдаемых, определенных выше, для вычисления выводимых частей состояния. Если у вас есть наблюдаемые объекты с именами «foo», «bar» и «baz», вы можете использовать вычисляемые свойства для создания, например, {foo, bar}, если оба определены, или null в противном случае. Этот новый уникальный объект необходим, помимо прочего, для запуска обнаружения изменений OnPush. Если свойство «baz» изменилось, вычисляемое свойство будет удобно использовать как старое значение, без нежелательных триггеров обнаружения изменений OnPush.

Автозапуск

Вот где происходит настоящая магия.

Автозапуск - это функция, которая:

  1. Вероятно, у вас есть в вашем ngOnInit (). Конструктор класса слишком ранний (например, Angular ChangeDetectorRef там недоступен).
  2. Вначале запускается один раз. MobX записывает, какие свойства (наблюдаемые и вычисленные) из MobX сохраняет доступ к ним, и запоминает свои зависимости.
  3. Запускается снова при изменении любой из ваших зависимостей.
  4. Остается «горячим», пока вы не откажетесь от подписки. autorun () возвращает вызываемое средство удаления, которое вы вызовете в своем ngOnDestroy для компонента.

Что находится в вашем autorun () в типичном приложении Angular? У вас может быть код, который:

  • Копирует значения из хранилища в локальные переменные компонента, которые используются из шаблона.
  • Запускает patchValue () в реактивной форме внутри компонента.
  • Выполняет некоторые настройки в последнюю минуту для данных, чтобы упростить доступ из шаблона.
  • Вызывает ChangeDetectorRef.detectChanges (), чтобы заставить Angular проверять изменения, если вы находитесь в компоненте ChangeDetectionStrategy.OnPush (и не инициировали изменение какого-либо ввода).

У одного компонента может быть много блоков autorun (). Чем меньше и крупнее блоки, тем точнее вы можете указать, как часто они срабатывают.

Однако автозапуск не ограничивается компонентами! Сервисы могут иметь собственный автозапуск, отслеживающий состояние, возможно, инициирующий HTTP-запросы, когда интересные данные доступны в магазинах, и отправляющие интересные ответы обратно в магазины, когда они возвращаются.

Разве для этого не нужна новая библиотека?

Не совсем. Core MobX отлично работает с Angular по схеме, упомянутой выше.

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

Вы вызываете startObserving (this, () = ›…) в ngOnInit () и stopObserving (this) в ngOnDestroy. Позже будет новый пост в блоге с еще несколькими подготовленными помощниками.

Также существует проект https://github.com/mobxjs/mobx-angular, который полностью отделяет компонент от обычного обнаружения изменений Angular. Он может работать для ваших нужд, но я полагаю, что он может вам не понадобиться, и работа напрямую с (уже простым) основным API MobX может помочь при отладке проблем в вашей собственной логике (например, почему это не изменилось? точка останова в моем автозапуске! )

Как насчет Rx Observables?

Мы начали с того, что передавали данные из MobX в качестве наблюдаемых Rx в наши компоненты, как описано здесь: https://netbasal.com/managing-state-in-angular-with-mobx-51191803e14f

Тем не менее, меня оставили в недоумении «да». Если вы просто используете autorun (), вы избегаете этой ненужной оболочки и избавляетесь от необходимости использовать асинхронные каналы. Вы просто назначаете новые неизменяемые ссылки (которые вы получили от @computed getters или autoruns) для своих компонентных переменных, и их детекторы изменений срабатывают.

Сам MobX, несмотря на его простоту и удобство использования, сам по себе представляет собой сложную реактивную систему. Это просто дает вам ту же мощность, которую вы получаете с Rx, с более дешевым ценником (нет необходимости делать combLatest (), switchMap () и т. Д., Чтобы выразить принципиально простые вычисления).

Как насчет NGRX?

Яркие глаза и пушистые хвосты, мы начали с NGRX; он имеет очень хорошую поддержку в отрасли, основан на сообществе React, любимом Redux, и продвигается группой горячих сторонников Angular. Так что это будет консервативный выбор по умолчанию, верно? Верно?

Лично для меня это был травмирующий опыт. Был один каталог с 5 файлами для представления чего-то, что было 5 строками с MobX - в основном массив.

Я хотел дать ему неделю на то, чтобы погрузиться в него, но думаю, мне удалось 2 дня нулевой продуктивности, прежде чем прекратить эксперимент. В прошлом я делал ужасные вещи (Symbian C ++, необработанное программирование макросов GObject, 4GL, Perl ...), но сейчас 2018 год, я не становлюсь моложе, и разработка интерфейса должна быть немного веселой и игривой - экспериментирую с разными схемами состояний и так далее должно быть естественной, возбуждающей частью работы.

Призыв к действию

Так что степень «авторитета вопросов» здесь уместна. Если мы рассматриваем MobX как лучшую мышеловку для Angular, мы должны действовать более последовательно. Мы должны начать писать инструменты разработчика, которые иллюстрируют поток данных на экране. За исключением всего остального, мы можем хоть немного пошуметь в блогах.