О чем этот пост?
В последнее время Redux стал очень популярным и показал большой потенциал. Однако, учитывая существование Meteor’s Tracker и Minimongo, неясно, какое место Redux занимает в приложениях Meteor. Этот пост призван начать обсуждение того, как Redux может вписаться в приложение Meteor. Я заинтересован в получении отзывов о том, что вы считаете наиболее подходящим способом сделать это.
Что такое Redux, Tracker или Minimongo?
Прежде чем продолжить, давайте кратко рассмотрим Redux, Tracker и Minimongo. Если вы уже знакомы с этими технологиями, вы можете пропустить этот раздел.
Трекер 🔗
- Meteor поставляется с системой отслеживания зависимостей, которая может отслеживать источники данных, такие как переменные сеанса или результаты запросов к базе данных и повторно отображать шаблоны, или выполнять другие вычисления всякий раз, когда происходят изменения. Это позволяет, например, когда реактивная переменная изменяет свое значение, шаблон повторно отображается для отображения нового значения без какой-либо дополнительной работы.
Минимонго 🔗
- Meteor хранит локальный кеш подмножества базы данных на стороне клиента, который будет обновляться с серверной частью. Это означает, что изменение в базе данных синхронизируется с кэшированной версией базы данных клиента, так что Tracker может выбрать это и повторно отобразить шаблон.
Редукс 🔗
- Redux — это контейнер с предсказуемым состоянием для Javascript. Другими словами, это просто объект, который содержит состояние приложения, с принципами, определяющими, как им можно манипулировать. Например, для приложения todo объект может выглядеть примерно так:
{ tasks: [ { name: “task1” state: “completed” }] }
- Вы поняли идею. Redux НЕ включен в Meteor, но многие были в восторге от того, что он может принести на стол, хотя все еще есть сомнения, действительно ли он добавляет какую-либо ценность метеору.
- Redux использует Действия и Редукторы. Действия объясняют, что что-то произошло (например, Добавить новую задачу), а редукторы объясняют, какие изменения в состоянии приложения происходят в ответ (например, добавление элемента в массив задач).
- Стоит отметить, что один из принципов Redux гласит, что редюсеры, модифицирующие состояние, должны быть чистыми функциями. Это означает, что они не мутируют состояние и не имеют побочных эффектов. Это примечательно, потому что методы Meteor не являются чистыми функциями, что приводит к интересным ситуациям в некоторых библиотеках, где методы Meteor используются в качестве редюсеров, а принципы Redux нарушаются.
- Чтобы узнать больше о Redux, ознакомьтесь с этим руководством, созданным Дэном Абрамовым, создателем Redux.
Зачем мне нужно сокращение в моем приложении Meteor?
Вы не знаете. Более простые приложения могут работать с использованием ReactiveDict, React setState (при условии, что вы используете реакцию) и другие методы. Однако по мере того, как все становится сложнее, приятно иметь одно место, которое дает вам представление обо всем приложении с высоты птичьего полета. Какая навигация активна? На какое представление смотрит пользователь? Их можно безболезненно выразить с помощью редукции. Кроме того, работа в стиле React и совместимость с Apollo могут послужить мотивацией для внедрения Redux в ваше следующее приложение Meteor.
Какое место Redux занимает в моем приложении Meteor?
С участием Meteor непросто увидеть, где Redux вступает в игру. Он заменяет Tracker и Minimongo? Если нет, дублирует ли Redux данные в minimongo? Как обновляются данные в Redux? Все это зависит от того, как Redux реализован в приложении Meteor. На данный момент существует несколько разных подходов, и каждый из них по-своему отвечает на поставленные выше вопросы.
В этом посте мы сосредоточимся на методе, описанном Абхи Айером в потрясающем учебнике из 5 частей. Этот метод работает вместе с Minimongo и Tracker, в то время как другие методы могут полностью исключить их из уравнения.
В нашем предпочтительном методе Redux предназначен для сохранения состояния пользовательского интерфейса. Например, какой элемент навигации активен, какое представление открыто и т. д. Однако, хотя Redux можно использовать для управления состоянием домена, в Meteor Mongo и Minimongo об этом можно позаботиться.
Рассмотрим приложение TODO в учебнике по приложению TODO от Abhi. Мы предоставим общий обзор того, как вещи связаны друг с другом в этом приложении (ссылка на Github).
Метеорные методы
Представьте, что нам нужно создать простое TODO-приложение. Во-первых, нам нужны методы Meteor, которые обновляют базу данных. Я буду использовать более описательное имя, чем те, которые используются в репозитории, чтобы отличить их от других подобных методов.
- (1): addTodoMeteorMethod(текст)
- (2): toggleTodoMeteorMethod(id)
Создатели действий
Далее нам нужно создать Создатели действий. Создатели действий — это методы, которые возвращают Действие, как показано ниже. Действие — это простой объект, указывающий на то, что должно произойти:
function addTodo(text) { return { type: ADD_TODO, text, } }
Однако в нашем случае, благодаря redux-thunk, который позволяет возвращать асинхронные функции как действия, а не простые объекты, наши создатели действий возвращают две функции (1), & (2), которые определено выше.
- (3): addTodoActionCreator(текст) (1)
- (4): toggleTodoActionCreator(текст) (2)
Обратите внимание, что эти создатели действий не являются чистыми функциями, поскольку они используют методы Meteor и изменяют базу данных, поэтому они оба имеют побочные эффекты. Но это нормально. Наши редюсеры должны быть чистыми функциями.
Редукторы
Помните, что редьюсеры принимают состояние и действие и возвращают новое состояние:
(previousState, action) => newState
Мы собираемся представить два редуктора, которые улучшают работу пользовательского интерфейса, фильтруя и разбивая список задач на страницы:
- (5): visibilityFilterReducer(previousState, action)
- (6): pageSkipReducer(предыдущее состояние, действие)
Обе эти функции в значительной степени возвращают переданное им действие. Например, рассмотрите возможность вызова наших редукторов с помощью следующего действия:
{type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_COMPLETED'}
Редьюсер возвращает «SHOW_COMPLETED», что является следующим состоянием:
Магазин
Все эти вещи кажутся красивыми, но где на самом деле хранятся состояния? В магазине происходит все волшебство. Магазин отвечает за три вещи:
- Удержание и возврат состояния приложения
- Разрешить слушателям подписываться на изменения (для этого мы используем mapStateToProps)
- Диспетчерские действия и побочные эффекты
(3), (4), (5) и (6) отправляются через магазин следующим образом:
- Store.dispatch(addTodo('новая задача')); (3)
- Store.dispatch({ тип: ‘SET_VISIBILITY_FILTER’, фильтр: ‘SHOW_COMPLETED’ }); (4)
Реагировать: провайдер
Мы установили, что все действия должны проходить через Store. Но как вещи связаны с интерфейсом (т.е. React)? Провайдер делает это с помощью connect. Это компонент React в React-Redux, который должен быть обернут вокруг всех других компонентов, чтобы он мог передавать Store дочерним компонентам.
React-редукс: подключиться
Как упоминалось выше, connect — это мост между React и Store.
- Connect предоставляет доступ к Store.dispatch через React Props, чтобы могли срабатывать побочные эффекты и действия. Это позволяет нам, например, отправлять addTodo из React при нажатии кнопки.
- Connect предоставляет доступ к подписке через реквизиты, которые являются реактивными через mapStateToProps — простую функцию, которая сопоставляет состояние Redux с реквизитами React, чтобы их можно было использовать в компоненте.
Код для mapStateToProps так же прост, как показано ниже:
function mapStateToProps(state) { return { visibilityFilter: state.visibilityFilter, pageSkip: state.pageSkip } }
Что случилось с Минимонго?
В приложении, описанном выше, мы управляли такими вещами, как фильтры и номера страниц (состояние пользовательского интерфейса) с помощью Redux, но мы хранили наши данные (состояние домена) в Mongo и Minimongo. Это означает, что доступ к данным по-прежнему осуществлялся через Подписаться и опубликовать Meteor. Однако можно также сохранить состояние домена в Redux Store, используя Tracker для поддержания его в актуальном состоянии.
// will run every time Messages changes Tracker.autorun(() => { store.dispatch({ type: 'SET_TODOS', todos: Todos.find().fetch() }); });
Обратите внимание, что Mongo.Collection.Observe можно использовать вместо трекера для более эффективного и мощного решения, но в этом примере Tracker предназначен для передачи идеи.
Альтернативные решения
То, что было описано выше, является одним из способов, которым Redux вписывается в приложение Meteor. Однако есть и другие способы, которые могут работать так же хорошо, но используют другие подходы.
- Redux-DDP можно использовать вместо хака Трекера выше. Этот подход использует прослушиватели событий DDP для обновления состояния приложения. Однако, учитывая неоднозначное будущее DDP в Meteor, это может быть не самое перспективное решение.
- Использование ReactiveDict: этот подход имитирует поведение Redux с использованием ReactiveDict, что в итоге приводит к аналогичному поведению. Обратите внимание, что в этом подходе Reducer имеет побочные эффекты и не является чистым, поэтому он нарушает принципы Redux.
Учитывая то, что мы наблюдали выше, не существует единого лучшего подхода к тому, где Redux должен находиться в приложении Meteor и за что он должен отвечать. Есть аргументы за и против каждого подхода. Мне интересно услышать, считаете ли вы, что Redux актуален, учитывая то, что уже предлагает Meteor, и если да, то где он должен вписаться.
Первоначально опубликовано на странице www.okgrow.com/posts/where-does-redux-fit-in-meteor.