Глоссарий
Это глоссарий основных терминов в Redux, наряду с их сигнатурами типа. Типы описаны при помощи Flow notation.
Состояние (State)
type State = any
Состояние (также дерево состояния) — широкое понятие, но в Redux API это, как правило, отсылка к единственному состоянию, которое управляется стором (store) и возвращается getState()
. Оно представляет собой все состояние Redux-приложения, которое обычно является объектом с глубокой вложенностью.
Как правило, состояние верхнего уровня — это объект или какая-то другая коллекция вида ключ-значение, например Map, но технически это может быть любой тип. Вместе с тем, вам нужно стараться поддерживать состояние сериализуемым. Не кладите внутрь ничего, что потом не сможете легко превратить в JSON.
Экшен (Action)
type Action = Object
Экшен — это простой объект, который представляет намерение изменить состояние. Экшены — единственный путь получить данные в сторе. Любые данные, будь то события UI, коллбэки сетевых запросов или любые другие ресурсы как веб-сокеты, должны быть в итоге обработаны, как экшены.
Экшены обязаны иметь поле type
, которое указывает тип производимого экшена. Типы также могут быть определены как константы и импортированы из другого модуля. Лучше использовать строки для type
, чем Символы, потому что строки сериализуемы.
Вся остальная структура, кроме type
, полностью на ваше усмотрение. Если вы заинтересованы, посмотрите Flux Standard Action для рекомендаций как нужно создавать экшен.
Также смотрите асинхронный экшен ниже.
Редюсер (Reducer)
type Reducer<S, A> = (state: S, action: A) => S
Редюсер (так же называемая, как функция-редюсер) — это функция, которая принимает аккумулятор и значение и возвращает новый аккумулятор. Они используются для редуцирования (сокращения) коллекции значений в единственное значение.
Редюсеры не уникальны для Redux — они являются фундаментальным понятием в функциональном программировании. Даже большинство нефункциональных языков, как JavaScript, имеют встроенное API для редуцирования. В JavaScript это Array.prototype.reduce()
.
В Redux, аккумулирумое значение — это объект состояния, а значения, которые должны быть аккумулированы — это экшены. Редюсеры расчитывают новое состояние, учитывая предыдущее состояние и экшен (action). Они обязаны быть чистыми функциями — функциями, которые возвращают одинаковый результат для переданных входных данных. Они также не должны иметь побочных эффектов (side-effects). Это то, что обеспечивает интересные возможности, такие как "горячая перезагрузка" (hot reloading) и путешествия во времени (time travel).
Редюсеры являются наиболее важным понятием в Redux.
Не размещайте вызовы API в редюсерах.
Функция-диспетчер (Dispatching Function)
type BaseDispatch = (a: Action) => Action
type Dispatch = (a: Action | AsyncAction) => any
Функция-диспетчер - это функция, которая принимает экшен или асинхронный экшен и далее может или не может отправить один или несколько экшенов в стор.
Мы должны различать функцию-диспетчер в целом и базовую функцию dispatch
, предоставляемую экземпляром стора без всяких мидлваров (middlewares).
Базовая функция dispatch всегда синхронно отправляет экшен в редюсер вместе с предыдущим состоянием, возвращенным из стора, для вычисления нового состояния. Оно ожидает экшен в виде простых объектов, готовых для использования в редюсере.
Мидлвар оборачивает базовую функцию dispatch. Это позволяет функции-диспетчеру обрабатывать асинхронные экшены в дополнение к обычным экшенам. Мидлвар может преобразовывать, задерживать, игнорировать или иным образом интерпретировать экшены или асинхронные экшены перед передачей их к следующему мидлвару. См. ниже для получения дополнительной информации.
Генератор экшена (Action Creator)
type ActionCreator = (...args: any) => Action | AsyncAction
Генератор экшена - это, совершенно очевидно, функция, которая создает экшен (action). Не следует путать эти два термина - еще раз, экшен - это структура данных, а генератор экшена - это фабрика, которая создает экшен (action).
Вызов генератора экшена только создает экшен, но не выполняет его. Вам нужно вызвать функцию стора dispatch
которая на самом деле вызывает изменения. Иногда мы говорим связанные генераторы экшенов имея ввиду функции, которые вызывают генератор экшена и сразу же отправляют его результат соответствующей части стора.
Если генератору экшена надо получить текущее состояние, выполнить вызов API или вызвать побочный эффект, как переход маршрутизации, это должно быть возвращено асихронным экшеном (async action) вместо обычного экшена.
Асинхронный экшен (Async Action)
type AsyncAction = any
Асинхронный экшен (async action) - это значение, которое передается в вызывающую функцию (dispatching function), но пока не готово для редюсера. Оно будет преобразовано при помощи мидлвара в экшен или набор экшенов перед отправкой в базовую функцию dispatch()
. Асинхронные экшены могут иметь различные типы в зависимости от используемых мидлваров. Они часто являются асихронными примитивами, как промисы (Promise) или thunk, которые не передаются в редюсер немедленно, а выполняют экшен, только когда операция завершена.
Мидлвар (Middleware)
type MiddlewareAPI = { dispatch: Dispatch, getState: () => State }
type Middleware = (api: MiddlewareAPI) => (next: Dispatch) => Dispatch
Мидлвар — это функция высшего порядка, которая создает функцию-диспетчер (dispatch function), возвращающую новую функцию-диспетчер. Она часто возвращает асинхронный экшен в экшен.
Мидлвары компонуемы с помощью функции композиции - это полезно для регистрации экшенов, выполнения побочных действий (side effects), таких как, маршрутизация или превращения асинхронного вызова API в серию синхронных экшенов.
См. applyMiddleware(...middlewares)
для более детальной информации по мидлварам.
Стор (Store)
type Store = {
dispatch: Dispatch
getState: () => State
subscribe: (listener: () => void) => () => void
replaceReducer: (reducer: Reducer) => void
}
Стор — это объект, который хранит дерево состояний приложения. В приложении должно быть только один стор, так построение происходит на уровне преобразователя (reducer).
dispatch(action)
базовая функция отправки (dispatch), описанная выше.getState()
возвращает текущее состояние стора.subscribe(listener)
регистрирует функцию, которая будет вызвана при изменении состояния.replaceReducer(nextReducer)
может быть использован для реализации горячей перезагрузки (hot reload) и разделения кода. Скорее всего Вы не будете использовать ee.
См. store API reference для получения дополнительной информации.
Генератор стора (Store creator)
type StoreCreator = (reducer: Reducer, initialState: ?State) => Store
Генератор стора — это функция, которая создает Redux-стор. Как и в случае с отправляющей функцией, мы должны различать базовый генератор стора, createStore(reducer, initialState)
экспортирумый из Redux, от генератора стора, возвращаемого из расширителей стора (store enhancers).
Расширитель стора (Store enhancer)
type StoreEnhancer = (next: StoreCreator) => StoreCreator
Расширитель стора — это функция высшего порядка, которая создает генератор стора, возвращающий новый, расширенный генератор стора. Это похоже на мидлвар тем, что позволяет вам изменять интерфейс в композиционном стиле.
Расширители стора аналогичны понятию - "компоненты высшего порядка" в React, которые также иногда называются "усилителями компонент".
Поскольку стора является не инстансом, а скорее объектом-коллекцией функций, то копии могут быть запросто созданы и модифицированы, без изменения оригинального стора. Пример в описании compose
демонстрирует это.
Скорее всего, вы никогда не будете писать расширитель стора, но вы можете использовать один предоставленный developer tools. Это то, что делает "путешествие во времени" (time travel) возможным без информирования приложения, о том, что происходит. Занятно, что реализация Redux мидлваров сама по себе является расширителем стора.