Сегодняшний пост будет посвящен тому, что происходит с store.dispatch(action) вызовами после dispatch вызова, вызванного в createStore (обсуждается в Части I этой мини-серии Redux). В качестве напоминания, приведенный ниже код был сгенерирован в Части I. Я просто добавлю вызов диспетчеризации, чтобы увеличить счетчик командной строки на 1.

Счетчик теперь увеличивается до входного числа плюс 1. Так что же здесь произошло? dispatch на самом деле очень короткий метод (всего 26 строк, включая пробелы), поэтому в этом сообщении в блоге будет предпринята попытка объяснить каждую строку. Вся рассылка приведена ниже (напомним, я использую Redux 4.0):

Сначала я хочу просмотреть комментарий над методом dispatch в исходном коде Redux. Части комментария относятся к действиям, которые являются Promises, которые Redux из коробки не поддерживает. Я пока пропущу эти разделы. Первый соответствующий раздел находится ниже:

Отправляет действие. Это единственный способ вызвать изменение состояния.

Функция reducer, используемая для создания хранилища, будет вызываться с текущим деревом состояний и заданным action. Его возвращаемое значение будет считаться следующим состоянием дерева, и слушатели изменений будут уведомлены.

Таким образом, вызов dispatch - единственный способ вызвать изменение currentState магазина. dispatch вызывается с action в качестве аргумента, который передается редуктору, изначально переданному createStore. Возвращаемое значение редуктора - это новое currentState дерева. Последняя часть предложения о слушателях изменений еще не имеет отношения к игрушечному приложению, которое я создаю, поэтому я пока проигнорирую его.

Как отмечалось ранее, dispatch принимает action в качестве аргумента, который должен быть POJO (помогает с redux-devtools), требует свойства типа и не может быть неопределенным.

@param {Object} действие Простой объект, представляющий… что изменилось. Рекомендуется сохранять сериализуемые действия, чтобы вы могли записывать и воспроизводить пользовательские сеансы или использовать путешествие во времени withredux-devtools. Действие должно иметь свойство type, которое не может быть undefined.. Для типов действий рекомендуется использовать строковые константы.

Начало отправки охватывает только эти базы и при необходимости вызывает ошибки:

Также существует условие, которое проверяет, что isDispatching истинно, и выдает ошибку, если это так. Мы встретили такой же тип isDispatching в Части I.

Причина этой ошибки состоит в том, чтобы предотвратить вызовы dispatch из reducer (отсюда и ошибка «Редукторы не могут отправлять действия»). Вызвать эту ошибку можно, передав хранилище в действие и вызвав dispatch из reducer, например:

Если reducer может вызывать dispatch, store.dispatch может повторяться бесконечно (store.dispatch(action) - ›currentReducer(currentState, action) -› store.dispatch(action) - ›currentReducer(currentState, action)…), и разработчик будет нести ответственность за обработку этой возможности. Я предполагаю, что разработчики Redux защищают разработчиков от самих себя.

Следующая часть dispatch - это блок try / finally, который устанавливает isDispatching в значение true (переменная, объявленная через let в createStore), устанавливает currentState в _42 _ (_ 43_ также объявляется через let в createStore), а затем в finally устанавливает isDispatching обратно в значение false . Опять же, isDispatching используется только в этой функции, чтобы предотвратить вызов dispatch в редукторе.

Кроме того, если вам интересно, почему здесь try / finally, цель состоит в том, чтобы Redux никогда не устанавливал isDispatching обратно на true. Это предотвратит повторное срабатывание редуктора (из-за вышеупомянутой ошибки Редукторы не могут отправлять действия). Я действительно узнал это, глядя на этот Redux PR, и конкретно на этот обмен:

Последняя часть dispatch перед оператором return - установить listeners array равным currentListeners, который затем устанавливается в nextListeners. Обе переменные *Listeners объявляются через let в createStore. Затем цикл for проходит по слушателям и вызывает каждого из них.

В этом игрушечном примере и currentListeners, и nextListeners являются пустыми массивами, поэтому нет слушателей для вызова.

Возвращаемое значение - это просто переданный ему action:

@returns {Object} Для удобства тот же объект действия, который вы отправили.

Почему это удобно, я пока не уверен, но пока буду доверять источнику.

Мы сделали это! Этот пост охватывает dispatch без набора слушателей. В следующем посте я буду генерировать слушателей через store.subscribe и анализировать, что происходит в этом цикле слушателей, когда слушатели существуют.