Выпущен MobX 3: очистка лука от кожуры

С радостью сообщаю, что MobX 3 общедоступен! Версия 3 не вводит много новых концепций и почти ничего не меняет в основном алгоритме. Но API получил много улучшений. Теперь API стал более согласованным и прокладывает путь к реализации Mobx на основе прокси (которая должна быть сделана после того, как все основные веб-браузеры поддержат этот шаг). Полную информацию обо всех критических и неразрывных изменениях можно найти в журнале изменений, но прочтите его суть.

Да, и домашняя страница MobX теперь официально называется https://mobx.js.org!

Совет от профессионалов: если вы хотите быстро выполнить миграцию, используйте строго типизированную среду (рекомендуется TypeScript), чтобы компилятор мог помочь :-).

Неочищенный репчатый лук

Самым важным изменением в MobX 3 является способ создания наблюдаемых структур данных. API MobX 2 имеет довольно много нестыковок и крайних случаев. Это была попытка сообщества изменить дизайн observable API. В самой длинной ветке системы отслеживания проблем до сих пор обсуждались многие варианты использования и шаблоны использования. Многие предложения были сбиты в воздухе, но я очень доволен конечным результатом.

Новый API следует «луковичному шаблону». API теперь красиво расслоен; каждый уровень API можно легко отсоединить, чтобы выявить функции более низкого уровня. Давайте быстро пройдемся по нему.

Функция / декоратор observable работает в основном так же, как в MobX 2. Есть 3 заметных изменения:

  1. По умолчанию объекты больше не улучшаются, а клонируются. Это согласуется с массивами и картами и прокладывает путь к прокси.
  2. Добавлена ​​поддержка карт ES6 (только строковые ключи).
  3. Значения функции без аргументов больше не преобразуются автоматически в вычисляемые свойства. Это должно избежать путаницы.

Не стесняйтесь пропустить оставшуюся часть этого раздела, если у вас нет опыта работы с MobX; это довольно подробно…

Наблюдаемый

Функция observable (data) создает новые наблюдаемые коллекции. Объект, карты, массивы или наблюдаемые в штучной упаковке. Если мы удалим наблюдаемый объект, вы обнаружите, что он просто вызывает один из следующих методов: observable.object, observable.map, observable.array и observable.box. Не стесняйтесь использовать эти методы напрямую вместо общего метода observable.

Коллекционные фабрики

Каждый из этих типов коллекций имеет одинаковую семантику: если вы присваиваете им ненаблюдаемое примитивное значение, MobX автоматически клонирует и преобразует этот объект в наблюдаемый. Вызов observable(newValue) перед сохранением этого нового значения. По умолчанию это обеспечивает глубокую наблюдаемость. Этот рекурсивный процесс можно описать как создание глубоких наблюдаемых данных.

Мелкие коллекционные фабрики

Однако иногда вам нужна коллекция, в которой MobX не пытается преобразовать данные в наблюдаемые. Например, при хранении элементов JSX или DOM или объектов, управляемых внешней библиотекой. Другими словами, иногда вам просто нужна неглубокая коллекция. Коллекция, которая сама по себе является наблюдаемой, но хранимые в ней значения - нет. Для этой цели MobX теперь также предоставляет функции для создания мелких коллекций: observable.shallowObject, observable.shallowMap, observable.shallowArray и observable.shallowBox. Кроме того, аналогично extendObservable, теперь есть extendShallowObservable.

Декораторы и модификаторы

Если вы используете декораторы, декоратор @observable применяет стратегию deep. Вы можете сделать это более явным, фактически используя декоратор @observable.deep. Точно так же есть @observable.shallow decorator, который преобразует любое значение, которое вы ему присваиваете, в неглубокую коллекцию (поддерживаются только массивы и карты). И, наконец, есть @observable.ref, который оставляет любое значение, которое вы присваиваете свойству, полностью как есть, и просто создает наблюдаемые ссылки на значение, которое вы ему присваиваете (аналогично observable.shallowBox).

Если вы не используете декораторы, вы все равно можете использовать эти стратегии при создании наблюдаемых объектов, вызывая эти декораторы как функцию. Например: const message = observable({ author: observable.ref(null) }). Эти новые модификаторы заменяют старые модификаторы asFlat, asMap и т.д. И, как вы уже могли догадаться, на этом мы пришли к сердцевине лука. Эти модификаторы используются внутри поверхностных и глубоких наблюдаемых коллекций.

Обработка ошибок

MobX 3 обеспечивает четкое поведение при обработке ошибок. В то время как MobX 2 приложил максимум усилий для восстановления после любых исключений, возникших при производной, семантика теперь четко определена:

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

Реакции всегда перехватывают исключения и по умолчанию просто записывают их в консоль. Это гарантирует, что если одна реакция вызовет исключение, это не повлияет / не предотвратит выполнение других реакций.

И вычисленные значения, и реакции теперь всегда восстанавливаются после исключений; то есть, даже если генерируется исключение, информация отслеживания сохраняется. Это означает, что они продолжат работу и восстановятся, если причина их исключения будет устранена. К реакциям можно прикрепить настраиваемое поведение обработки ошибок, присоединив обработчик onError. Также можно прикрепить глобальный обработчик ошибок, что удобно для мониторинга и тестирования.

Дальнейшие заметные изменения

MobX 3 теперь поставляется с типами Flow! Обратите внимание, что типизация потока не охватывает все, поскольку некоторые шаблоны перегрузки могут быть выражены в TypeScript, но (afaik) не в Flow.

Теперь можно создавать действия, которые автоматически привязываются к правильному this, аналогично autobind. Для этого можно использовать action.bound(fn) или @action.bound вместо action(fn).

API reaction и computed был упрощен, и теперь оба они принимают объекты параметров вместо множества параметров. Подробности смотрите в журнале изменений.

Обратные вызовы, переданные toobserve, теперь всегда вызываются с объектом изменения. В MobX 2 наблюдатели вычисляемых значений и упакованных наблюдаемых объектов вызывались с (newValue: T, oldValue: T), это было изменено на (change: { newValue: T, oldValue: T }), что согласуется с spy, intercept и observe для коллекций.

Из ядра удалено структурное сравнение наблюдаемых. Эта функция практически не использовалась, а если и использовалась, то часто в местах, где наблюдаемые в штучной упаковке / ссылочные наблюдаемые были бы более подходящим решением, например, при работе с неизменяемыми объектами. По-прежнему возможно создание структурных сравнительных вычислений ((@)computed.struct) и реакций (у которых есть опция для этого).

transaction устарел в пользу runInAction, который обеспечивает то же самое.

В целом, вероятно, ничего особенного или нового, но есть множество небольших улучшений, которые делают API более последовательным. Миграция не должна быть слишком сложной. Особенно, если вы еще не используете модификаторы, все должно быть просто. Я очень горжусь тем, что после этого релиза количество открытых проблем сократилось примерно до 25! Что, на мой взгляд, очень мало для такого сложного и популярного проекта, как MobX!

За это я хочу поблагодарить всех людей, которые отвечают на новые вопросы на Github и в канале Gitter. Ваши ответы на вопросы новичков и участие в обсуждениях дизайна неоценимы! Большой привет @agambit @andykog, @benjamingr, @capaj, @jabx, @mattruby, @strate, @spion, @urugator и многим другим!

Помните, что полный список изменений со всеми подробностями можно найти здесь!

А теперь… вернемся к дереву состояний mobx. Это становится потрясающе (с большим вкладом и отличными идеями от @mattiamanzati). Там есть доклад на конференции, 200 звездочетов… но пока нет настоящего релиза :). Так что следите за обновлениями, если вас интересует самоуверенный контейнер с реактивным состоянием!

\ * это дескрипторы GitHub, а не twitter ;-)