Мидлвары (middlewares) — это функции, которые последовательно вызываются в процессе обновления данных в хранилище. Они относятся к продвинутым техникам использования Redux.
В этом уроке мы разберем, как подключать и использовать мидлвары. Они помогают нам подключать различные библиотеки, причем с самого начала использования их в React.
Общий принцип такой:
Схематично этот принцип можно показать так:
Такая организация позволяет программистам расширять библиотеки новой функциональностью, не переписывая исходный код Redux под конкретную задачу.
Мидлвары используются в таких задачах, как:
Рассмотрим типичную структуру мидлвары, которая отвечает, например, за логирование. Логирование будем осуществлять с помощью методов console.info()
, console.groupEnd()
, console.log()
. Любая мидлвара в Redux — это композиция из трех вложенных функций:
// Мидлвара со вложенными стрелочными функциями
const logger = (store) => (next) => (action) => {
console.group(action.type);
console.info('dispatching', action);
const result = next(action);
console.log('next state', store.getState()); // выводим текущее состояние в консоль
console.groupEnd();
return result;
};
У всех мидлвар одинаковая структура из трех компонентов. Рассмотрим ее на примере выше:
Внешняя функция
Именно она является мидлварой и передается в метод applyMiddleware()
. Функция получает на вход объект store
, который содержит методы dispatch()
и getState()
для работы с флоу Redux.
Первая вложенная функция
Её аргументом будет особая функция next()
. Вызов этой функции в теле мидлвары с действием в качестве аргумента может прокидывать действие дальше по цепочке мидлвар.
Но если next()
вызван в последней мидлваре в цепочке (цепочка может состоять и из одной мидлвары), она диспатчит действие, отправляя его в редьюсер и вызывая обновление стейта.
Вторая вложенная функция
Это функция, принимающая в качестве аргумента действие action
при его диспатчинге. Всякое действие в приложении, отправляемое в редьюсер, будет перехватываться мидлварой.
Мидлвара может содержать асинхронную логику. В этом случае логгер не блокирует обновление стора, действие передаётся по цепочке мидлвар вплоть до редьюсера, вызывая обновление стейта строчкой const result = next(action);
.
Только потом, уже после цепочки мидлвар и обновления стейта, мы логируем новое состояние стора. Таким образом, все инструкции в логгере после вызова next()
выполняются как бы в будущем, в котором последующие мидлвары и редьюсер уже закончили работу.
Рассмотрим другой пример:
const addFinishText = (store) => (next) => async (action) => {
const result = next(action);
if (action.type !== 'TASK_FINISH') {
return result;
}
const user = await axios.get(`/users/${result.payload.userId}`);
result.payload.task.text = [result.payload.task.text, `Задачу завершил ${user.name}`].join('. ');
return result;
};
Мидлвара добавляет текст о завершении задачи с именем пользователя, кто завершил эту задачу. Она проверяет тип действия, если тип не относится к завершению задачи 'TASK_FINISH', то мидлвара завершает работу. Если тип соответствует, то делается запрос на получение данных о пользователе и обновляется текст в результирующих данных.
Теперь посмотрим, как подключить мидлвары:
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
const store = createStore(
reducer,
applyMiddleware(thunk)
)
Выше вы видите мидлвару thunk. Перед тем, как передать ее в функцию createStore
, нужно применить к ней функцию applyMiddleware
. Таким образом стор узнает о существовании мидлвары.
В общем случае она принимает три параметра:
Передача начального состояния и мидлвары опциональны. В примере выше мидлвара передается вторым параметром. Функция createStore
проверяет тип второго параметра и в зависимости от этого понимает, что перед ней: начальное состояние или мидлвара.
Если мидлвар несколько, придется воспользоваться еще одной функцией:
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import logger from 'redux-logger';
const store = createStore(
reducer,
/* preloadedState, */
compose(
applyMiddleware(thunk),
applyMiddleware(logger)
),
)
В этом случае в хранилище передается результат функции compose()
, при этом функция compose()
принимает на вход мидлвары.
Теперь мы подобрались к главному. Для Redux написано специальное браузерное расширение Redux DevTools. Установите его в свой браузер.
Ниже код подключения этого расширения к хранилищу:
const reduxDevtools = window.__REDUX_DEVTOOLS_EXTENSION__;
const store = createStore(
reducer,
/* preloadedState, */
reduxDevtools && reduxDevtools(),
);
Обратите внимание, что при работе с расширением функция applyMiddleware
не требуется.
В будущих уроках вам не придется подключать расширение руками. Мы уже сделали это за вас. Все, что нужно — установить его и не забывать им пользоваться. Это ваш главный помощник в отладке на протяжении всего курса.
Вам ответят команда поддержки Хекслета или другие студенты.
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
Наши выпускники работают в компаниях:
Зарегистрируйтесь или войдите в свой аккаунт