Или просто хороший учебник по MobX

Framework Wars… НЕ

Я начал свое путешествие в сказочную страну Frameworks с Vue и этой удивительной серии от Laracast. Я слышал о React, но тогда, когда я смотрел на JSX, мне это показалось мерзостью! Смешивание тегов html с логикой JS? Разве они не слышали о шаблонах проектирования и разделении задач? Ради бога, почему бы просто не использовать JQuery для создания мигающего текста?

Но потом я изучил JS, а не JQuery JS * ( трюки с DOM), а JS как язык разработки, элегантный выразительный инструмент для управления данными, язык с красивыми методами для работы с массивами, Строка и объекты. И то, что вы не можете сделать с ванильным JS, скорее всего, для этого есть Lodash или наверняка есть пакет NPM. (npm install make-me-a-sandwich Лол!)

После всего этого я еще раз взглянул на React и… я сразу влюбился! Где Vue похож на html с добавленной функциональностью (v-if, v-for...), JSX - это простой JS, который генерирует DOM. На самом деле я не пытаюсь начать здесь войну фреймворков. В настоящее время у меня работают приложения Vue и React, и я смог найти все инструменты, которые мне нужны в обеих средах для выполнения моей работы. Выбор действительно сводится к личным предпочтениям или предпочтениям вашей компании / команды.

Но React ...

Для новичка в React казалось, что Redux - это хранилище по умолчанию, как и Vuex для Vue, поэтому я решил изучить Redux ... и, просмотрев полную серию статей о яйцеголовых примерно 3 раза и столько же раз просматривая документацию, я все еще чувствовал себя так, как будто я понятия не имел, что делаю. Написание чего-либо, кроме тривиального редуктора, было головной болью. Нормализованные данные, реляционные таблицы, неизменяемость и технология БД - все это казалось предварительными требованиями для Redux! Я многому научился, но не настолько, чтобы чувствовать себя хоть сколько-нибудь продуктивно. Затем есть обертки для Redux и функций высокого порядка для генерации других функций и рецептов редукторов ... Я снова почувствовал себя стажером, не имея возможности завершить свой проект, потому что я не знал, как создать простое хранилище и сделать свое приложение реагировать на это! 😥

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

Я пропустил дни Vuex, в которых все просто работало, изменяемое состояние не было грехом, и независимо от того, где я вызывал действие магазина, все приложение всегда было синхронизировано. Но мне тоже очень понравился React, поэтому я начал смотреть, могу ли я использовать Vuex на React (по-видимому, нет), но в поиске я наткнулся на MobX. У него были смелые претензии:

MobX снова упрощает управление состоянием, решая основную проблему: он делает невозможным создание несогласованного состояния. *

Я снова направился в яйцеголовый, чтобы посмотреть видеоуроки. Они были хорошими, но не повезло! create-react-app не поддерживает декораторы, и вы не получите много примеров того, как что-то делать без них. Затем есть mobx-state-tree, который утверждает, что он самоуверен (и это еще не все!), И опять же, я понятия не имел, как что-то делать и что происходит! Видео научили меня делать довольно приличный счетчик, и mobx-state-tree казалось, что я пишу приложение для корпоративного банковского обслуживания, но я не мог найти средний уровень сложности.

Мне очень понравился React, поэтому я вернулся к Redux, но не смог заставить его работать, поэтому снова неохотно дал MobX еще одну попытку ... «И, наконец, я увидел свет; И туман рассеялся »

Хочу показать, что MobX проще в использовании, чем вы думаете. Мы собираемся использовать MobX, чтобы делать больше, чем просто считать вверх и вниз, и это проще, чем реализация mobx-state-tree.

Магазин

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

Отправной точкой является чистое create-react-app приложение, а вот store.js:

🙄 Пусть вас не пугает длина, на самом деле это довольно просто, методы студентов и курсов одинаковы.

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

Сначала мы просто объявляем const store как первый параметр observable(). * Вот как вы объявляете наблюдаемое без использования синтаксиса декоратора (@observable).

Внутри объекта, переданного в observable(), есть три места для размещения данных: студенты, курсы и зачисление, и они определены как observable.map(). Если вы впервые сталкиваетесь с Картой, не волнуйтесь, это просто причудливый объект с удобным способом доступа к содержимому в нем (сеттеры и геттеры). В простом объекте JS доступ к данным осуществляется следующим образом: object.key1.key2 или object['key1']['key2']. На карте доступ к ним осуществляется следующим образом: object.get('key1').get('key2'). У этого есть несколько преимуществ, и в этом конкретном проекте это спасло меня от использования большого количества _.set() и _.assign() (от Lodash).

Затем идут методы магазина для добавления, обновления и удаления студентов и курсов из магазина. Они просто .set() с некоторой обработкой ошибок.

Следующий интересный момент касается обработки регистрации. Эта идея определенно имеет привкус Redux (Отношения и таблицы), и в данном случае она полезна. Я создаю объект, ключ которого равен идентификатору курса, а значение представляет собой массив идентификаторов зачисленных студентов. Это выглядит так:

{
   course1: ['student1', 'student2', 'student3'],
   course2: ['student4', 'student5', 'student6'],
}

Действие происходит в методе enrolledStudents. Давайте разберемся: он возвращает computed(() => {...}) функцию, которая представляет собой выражение MobX, которое отслеживает изменения в элементах внутри него и автоматически обновляет его значение. Ничего особенного. Затем он получает элемент в карте зачисления, который соответствует идентификатору курса, переданному в качестве аргумента, который возвращает массив идентификаторов студентов. Затем .map() в массиве заменяет идентификатор каждого студента на весь объект ученика. Обратите внимание, что последний lonely .get() применяется к computed() и для получения фактических данных.
Таким образом, результатом метода enrolledStudents является массив всех объектов студентов, зарегистрированных на конкретном курсе, извините, наблюдаемый массив , поэтому любые изменения данных внутри функции будут обновлять возвращаемое значение и выполнять соответствующие повторные отрисовки! 🤩

Вот простой компонент React, чтобы продемонстрировать это на практике:

Это довольно стандартные компоненты React, за исключением observer и store.

Сначала определяются и добавляются в магазин пара студентов и курс. Затем student1 зачисляется на курс. Затем мы сопоставляем метод enrolledStudents из магазина, используя идентификатор курса для списка студентов, которых я хочу, и результаты ожидаются.

Самое интересное происходит, когда вы нажимаете кнопку «Зачислить студента 2».
В магазине идентификатор студента добавляется в массив соответствующей карты курса, и MobX заботится о том, чтобы все это синхронизировалось, правильно вычислить значение enrolledStudents , и выполнить соответствующие повторные отрисовки. И все это происходит из-за L39, где мы оборачиваем StudentsList внутрь observer()!

Обратите внимание, что ваши компоненты могут получить доступ к магазину разными способами. Вы можете импортировать компонент из файла, как и в предыдущем примере, вы можете передать его как опору из родительского контейнера, или вы можете использовать утилиты mobx-react provider / inject (в моем случае я могу импортировать store всякий раз, когда Мне необходимо).

Заключение

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