JavaRush /Курсы /Модуль 3: React /Что такое Middleware в Redux и зачем он нужен

Что такое Middleware в Redux и зачем он нужен

Модуль 3: React
7 уровень , 0 лекция
Открыта

Middleware

Привет! Сегодня мы начинаем разговор о Middleware, который является важной частью работы с Redux. Представьте, что Redux — это аэропорт управления состояниями вашего React-приложения. Действия (actions) — это авиарейсы, которые перевозят данные из одного города (компонента) в другой (редьюсер). И вот в этом аэропорту есть службы безопасности — это и есть Middleware. Их задача — перехватывать действия, проверять, изменять их или просто наблюдать за ними, прежде чем они попадут к редьюсеру.

Middleware позволяют вам:

  1. Выполнять дополнительные действия перед тем, как действие достигнет редьюсера.
  2. Обрабатывать асинхронные операции, такие как запросы к API.
  3. Логировать информацию о действиях и состоянии приложения.
  4. Обрабатывать ошибки и отменять действия при необходимости.

Официальная документация Redux — Middleware — помогает глубже понять, что это за зверь, но мы сегодня разберём всё на практике.

Концепция Middleware в Redux

Redux по своей сути синхронен. Если вы отправляете действие dispatch, редьюсер мгновенно обрабатывает его и генерирует новое состояние. Но в реальном мире приложения часто взаимодействуют с внешними системами: делают запросы к API, взаимодействуют с базой данных или обрабатывают таймеры. Middleware вмешивается в этот процесс и добавляет возможность "куда-нибудь заскочить" перед тем, как действие попадёт в редьюсер.

На практике Middleware выглядит как функция между отправкой действия dispatch и его обработкой редьюсером.

Визуализация процесса:

Action Dispatch --> Middleware --> Reducer --> New State

Middleware интерпретирует действия, может их изменить, дополнить или просто пропустить дальше.

Пример использования Middleware

Давайте нырнём в код. Представьте, что вы хотите создать Middleware, который логирует каждое отправляемое действие и текущее состояние.

Пример логирующего Middleware

import { Middleware } from 'redux';

// Это наш кастомный логирующий Middleware
const loggerMiddleware: Middleware = (store) => (next) => (action) => {
  console.log('Dispatching action:', action);
  const result = next(action); // Передача действия дальше (в редьюсер)
  console.log('Next state:', store.getState());
  return result;
};

export default loggerMiddleware;

Что здесь происходит?

  1. store — объект Redux-хранилища.
  2. next — функция, которая передаёт текущее действие следующему в цепочке (или редьюсеру, если Middleware последний).
  3. action — текущее действие, которое отправлено через dispatch.

Подключение Middleware к Redux Store

Middleware нужно зарегистрировать в Redux-хранилище, чтобы оно начало работать. Это делается с помощью функции applyMiddleware из redux.

import { createStore, applyMiddleware } from 'redux';
import rootReducer from './reducers'; // Ваши редьюсеры
import loggerMiddleware from './middlewares/loggerMiddleware'; // Наш логгер

// Создаём хранилище с подключением Middleware
const store = createStore(
  rootReducer,
  applyMiddleware(loggerMiddleware)
);

export default store;

Теперь при каждом вызове dispatch в store будет логироваться информация о действии и следующем состоянии.

Асинхронные действия и роль Middleware

Redux отлично подходит для синхронных данных, но как быть, если нам нужно дождаться ответа от API или запустить таймер? Здесь тоже помогает Middleware.

Без Middleware: асинхронный запрос

Допустим, вы хотите загрузить данные с API. Без Middleware код в компоненте может выглядеть так:

import React, { useEffect } from 'react';
import { useDispatch } from 'react-redux';

const MyComponent: React.FC = () => {
  const dispatch = useDispatch();

  useEffect(() => {
    const fetchData = async () => {
      const response = await fetch('/api/data');
      const data = await response.json();
      dispatch({ type: 'DATA_LOADED', payload: data });
    };

    fetchData();
  }, [dispatch]);

  return <div>Loading...</div>;
};

Здесь всё работает, но как-то грязно. Асинхронная логика оказывается "захардкоженной" в компоненте. Это делает тестирование и поддержку сложнее.

Middleware для асинхронных запросов

Middleware вроде Redux Thunk или Redux Saga позволяют выносить асинхронную логику из компонентов, делая код чище.

Пример использования Thunk будет рассмотрен в следующей лекции, но вот пример "ручного" Middleware для обработки асинхронных действий:

const asyncMiddleware: Middleware = (store) => (next) => async (action) => {
  if (typeof action === 'function') {
    // Если action — это функция, вызываем её с dispatch и getState
    return action(store.dispatch, store.getState);
  }

  return next(action); // Для обычных действий просто передаём их дальше
};

Теперь вы можете отправлять в dispatch не просто объект, а функцию:

const fetchData = () => async (dispatch: any) => {
  try {
    const response = await fetch('/api/data');
    const data = await response.json();
    dispatch({ type: 'DATA_LOADED', payload: data });
  } catch (error) {
    dispatch({ type: 'API_ERROR', payload: error.message });
  }
};

// Используем в компоненте
dispatch(fetchData());

Типичные ошибки и подводные камни

  1. Забытая передача действия дальше. Если вы создаёте кастомное Middleware, обязательно вызывайте next(action), иначе действие "застрянет".

    // Ошибка: действие не дойдёт до редьюсера
    const brokenMiddleware: Middleware = () => () => () => {
      console.log("Oops!");
    };
    
  2. Избыточное использование Middleware. Не стоит создавать Middleware для задач, которые проще решить обычным кодом. Иногда проще написать чистую функцию в редьюсере или компоненте.

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

Когда и зачем использовать Middleware?

  1. Асинхронные действия. Если приложение активно взаимодействует с сервером (API-запросы), Middleware поможет поддерживать статус-код и обработку ошибок централизованными.

  2. Логирование. Важный инструмент для отладки в процессе разработки.

  3. Обработка ошибок. Middleware может «ловить» ошибки, возникающие в процессе выполнения действий, и логировать или обрабатывать их.

  4. Сложная бизнес-логика. Когда редьюсеры слишком "нагружаются" дополнительными вычислениями, Middleware позволяет перенести логику.

1
Задача
Модуль 3: React, 7 уровень, 0 лекция
Недоступна
Фильтрация действий с помощью Middleware
Фильтрация действий с помощью Middleware
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ