Middleware (усилители)

Middleware (Усилители).

Прежде чем мы сможем создавать асинхронные действия, поговорим об усилителях и напишем, обещанный ранее усилитель - логгер.
Усилители, это middleware. Суть middleware функций, взять входные данные, добавить что-то и передать дальше.
Например: есть конвейер, по которому движется пальто. На конвейере работают Зина и Людмила. Зина пришивает пуговку, Людмила прикладывает бирку. Внезапно, появляется middleware Лена, встает между Зиной и Людмилой и красит пуговку в хипстерский модный цвет. Так как Лена после покраски не уносит пальто с собой, а передает дальше, то Людмила как ни в чем не бывало приделывает бирку и пальто готово. Только теперь оно хипстерское. Усиленное.
Для лучшего понимания, предлагаю написать бесполезный усилитель, выдающий console.log('ping'), на каждое действие. При этом, мы будем использовать предложенный redux метод добавления усилитей с помощью applyMiddleware.
Обновим файл конфигурации store:
store/configureStore.js
1
import { createStore, applyMiddleware } from 'redux'
2
import { rootReducer } from '../reducers'
3
import { ping } from './enhancers/ping' // <-- подключаем наш enhancer
4
5
export const store = createStore(rootReducer, applyMiddleware(ping)) // <-- добавляем его в цепочку middleware'ов
Copied!
Напишем усилитель:
store/enhancers/ping.js
1
/*eslint-disable */
2
export const ping = store => next => action => {
3
console.log('ping')
4
return next(action)
5
}
6
/*eslint-enable */
Copied!
Боюсь, здесь не обойтись без ES5 версии:
1
var ping = function ping(store) {
2
return function (next) {
3
return function (action) {
4
console.log('ping');
5
return next(action);
6
};
7
};
8
};
Copied!
Поехали:
  • eslint-disable - просто выключает проверку этого блока "линтером".
  • ping - это функция, которая возвращает функцию. Middleware - это всегда функция, которые обычно возвращают функцию, если только целью middleware не является прервать цепочку вызовов.
  • в функциях, у нас становятся доступными аргументы, которые мы можем использовать во благо приложения:
    • store - redux-store нашего приложения;
    • next - функция-обертка, которая позволяет продолжить выполнение цепочки;
    • action - действие, которое было вызвано (как вы помните, вызванные действия - это store.dispatch)
ping-logger
Сейчас, при клике на кнопки, у нас в консоли появляется строка ping. Давайте изменим ее, написав простейший логгер:
store/enhancers/ping.js
1
/*eslint-disable */
2
export const ping = store => next => action => {
3
console.log(
4
`Тип события: ${action.type}, дополнительные данные события: ${
5
action.payload
6
}`
7
)
8
return next(action)
9
}
10
/*eslint-enable */
Copied!
Я использовал новый строковый синтаксис. В прошлом, наш console.log выглядел бы так:
1
console.log('Тип события: ' + action.type + ', дополнительные данные события: ' + action.payload)
Copied!
Покликайте на кнопки, результат должен быть следующим:
ping-logger-with-type

Redux-logger

Отбросим наш велосипед и поставим популярный логгер.
1
npm i --save-dev redux-logger
Copied!
Удалите папку enchancers, и измените configureStore.
src/store/configureStore.js
1
import { createStore, applyMiddleware } from 'redux'
2
import { rootReducer } from '../reducers'
3
import logger from 'redux-logger'
4
5
export const store = createStore(rootReducer, applyMiddleware(logger))
Copied!
Можете проверить - логгер достаточно информативный и удобен в использовании.
redux-logger
Таким образом, усилители - отличный способ добавить в наш процесс обработки действий некую прослойку с необходимой функциональностью.
Одним из популярнейших усилителей, является redux-thunk, который мы как раз и будем использовать для создания асинхронных действий.
Исходный код на текущий момент.