Владислав Калачев

Пишем свой middleware для Redux

63

Доброго времени суток, друзья. В данной статье мы разберем понятие middleware в Redux и напишем свою небольшую Redux-middleware для логирования. Давайте обо всем по порядку.

Видео на эту тему.

Что такое middleware и зачем они нужны?

Само понятие middleware довольно-таки старая концепция. Если посмотреть на понятие в общем, то это промежуточное программное обеспечение для среднего слоя программы. 

То есть, по сути, это просто некая программа, которая выполняет определенные промежуточные действия или вычисления и передает их другой программе.

Давайте теперь посмотрим на это понятие в Redux. Redux-middleware является функция, которая получает данные после отправки экшена. Далее она может их проверить или сделать что-то с ними и затем передать дальше по цепочке в редьюсер.

Благодаря middleware в Redux имеется замечательная возможность производить нужные промежуточные действия в момент, когда пользователь взаимодействует с интерфейсом. Например, мы можем логировать данные, получать дополнительные данные, создавать нужные задержки и тд.

Пишем свою миделвару Logger для Redux 

Давайте перейдем наконец к практике и напишем свою миделвару. Для этого создадим функцию logger, которая принимает в параметрах весь store. Функция logger будет возвращать анонимную функцию и получать в аргументе функцию next, которая на самом деле является функцией dispatch. После чего нам нужно вернуть функцию next с переданным в нее параметром action. Звучит немного запутанно, поэтому давайте опишем эту конструкцию в коде, используя ES5.

В самой функции нам потребуется воспроизвести следующую логику:

1. Проверяем начальное состояние store

2. Проверяем action

3. Передаем через параметр функции next полученный action для передачи его редьюсеру

4. Снова проверяем store

5. Возвращаем результат next(action) из функции logger

Пример(ES5):


var logger = function logger(store) {
 return function (next) {
      return function (action) {
        console.log("dispatching", action.type);
        console.log("prev state", store.getState());
        console.log("action", action);
        result = next(action);
        console.log("next state", store.getState());
        return result;
    };
 };
};

У вас может появиться вопрос: «Откуда в аргументах logger вдруг появился доступ к store, функциям next и action?» Все благодаря функции applyMiddleware и замыканию. Каждый последующий вызов функции logger получает из области видимости функции applyMiddleware новые параметры, которые можно использовать внутри самой миделвары.

Благодаря стрелочным функциям и замыканию можно более компактно описать данную конструкцию.

Пример:


const logger = store => next => action => {
  let result;
  console.groupCollapsed("dispatching", action.type);
  console.log("prev state", store.getState());
  console.log("action", action);
  result = next(action);
  console.log("next state", store.getState());
  console.groupEnd();
  return result;
};

В коде выше для визуальной группировки логов используются не очень распространенные функции console.groupCollapsed() и console.groupEnd().

Как добавить миделвару в Redux?

Чтобы инициализировать миделвару logger в приложении, нужно добавить ее в функцию applyMiddleware, которая импортируется из самого redux, и передать вторым параметром в createStore.

Пример:


const middleware = applyMiddleware(logger);
const store = createStore(reducers, middleware);

Важно! Количество миделвар, которые можно передать в applyMiddleware не ограничено, их можно добавлять сколько угодно, через запятую.

Добавляя миделвары, следует помнить, что последовательность их передачи в параметры функции applyMiddleware тоже важна, так как создается цепочка вызовов и миделвары будут вызываться последовательно, передавая экшен от одной к другой с последующей передачей редьюсеру.

Небольшое отступление: если вы решили написать свою собственную миделвару, вы можете посмотреть на уже реализованные (например тут ) и использовать их, так как с большей вероятностью вашу проблему уже решили другие разработчики.

Пример нескольких middleware

Для большей наглядности приведу ниже несколько примеров Redux-middleware, которые могут быть вам полезны.

1. Позволяет отправлять промисы с экшеном. Если промис resolve, то его ответ будет отправлен как action.

Пример:


const promiseMiddleware = store => next => action => {
  if (typeof action.then !== 'function') {
    return next(action)
  }
  return Promise.resolve(action).then(store.dispatch)
}

2. Позволяет использовать функцию вместо экшена. Данная миделвар является очень популярной и велика вероятность, что вы с ней уже знакомы.


const thunkMiddleware = store => next => action =>
  typeof action === 'function' ?
    action(store.dispatch, store.getState) :
    next(action)

3. Позволяет отправлять action, в который можно передать количество миллисекунд в поле meta.delay для задержки выполнения данного экшена.


const schedulerMiddleware = store => next => action => {
  if (!action.meta || !action.meta.delay) {
    return next(action)
  }

  const id = setTimeout(
    () => next(action),
    action.meta.delay
  )

  return function cancel() {
    clearTimeout(id)
  }
}

Заключение

Сегодня мы рассмотрели подробно понятие middleware. Написали свою Redux-middleware для логирования экшенов и стора. В статье приведены примеры кода нескольких миделвар которые могут использоваться в вашей ежедневной работе или для образовательных целей. Надеюсь, что данный материал был вам полезен. Учитесь, думайте, пишите код. Удачного кодинга, друзья!

Подписывайтесь на наш канал в Telegram и на YouTube для получения самой последней и актуальной информации.

0

Комментарии:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *