О чем этот пост?

В последнее время 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.