← Назад к вопросам

Как Redux Thunk и Redux Saga подключаются к Redux?

2.3 Middle🔥 191 комментариев
#State Management#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Подключение Redux Middleware: Thunk и Saga

Redux Thunk и Redux Saga - это middleware, которые расширяют функциональность Redux для обработки асинхронных операций. Они подключаются к Redux через систему middleware при создании store.

Что такое Middleware в Redux

Middleware - это функция, которая перехватывает actions перед тем, как они достигнут reducer. Это позволяет:

  • Обрабатывать асинхронные операции
  • Логировать действия
  • Отправлять дополнительные actions
  • Изменять поведение dispatch

Redux Thunk

Redux Thunk позволяет action creators возвращать функции вместо обычных объектов.

Установка и подключение

npm install redux-thunk

Подключение при создании store

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';

const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);

Использование Thunk

// Обычный action creator возвращает объект
const actionA = () => ({ type: 'ACTION_A' });

// Thunk action creator возвращает функцию
const fetchUsers = () => {
  return async (dispatch) => {
    dispatch({ type: 'FETCH_USERS_REQUEST' });
    try {
      const response = await fetch('/api/users');
      const data = await response.json();
      dispatch({ 
        type: 'FETCH_USERS_SUCCESS', 
        payload: data 
      });
    } catch (error) {
      dispatch({ 
        type: 'FETCH_USERS_FAILURE', 
        payload: error.message 
      });
    }
  };
};

dispatch(fetchUsers());

Преимущества Redux Thunk

  • Простая и лёгкая в изучении
  • Малый размер (~1KB)
  • Легко отлаживать
  • Минимальный overhead

Недостатки Redux Thunk

  • Сложнее тестировать
  • Плохо масштабируется на больших проектах
  • Сложная логика асинхронных потоков требует callback hell'а
  • Сложно отменять операции

Redux Saga

Redux Saga использует генераторы JavaScript для управления асинхронными эффектами.

Установка и подключение

npm install redux-saga

Подключение при создании store

import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import rootReducer from './reducers';
import rootSaga from './sagas';

const sagaMiddleware = createSagaMiddleware();

const store = createStore(
  rootReducer,
  applyMiddleware(sagaMiddleware)
);

// Запустить saga после создания store
sagaMiddleware.run(rootSaga);

export default store;

Использование Saga с генераторами

import { call, put, takeEvery } from 'redux-saga/effects';

// Вспомогательная функция для API запроса
const fetchUsersAPI = async () => {
  const response = await fetch('/api/users');
  return response.json();
};

// Saga - это генератор функция
function* fetchUsersSaga() {
  try {
    yield put({ type: 'FETCH_USERS_REQUEST' });
    const data = yield call(fetchUsersAPI);
    yield put({ 
      type: 'FETCH_USERS_SUCCESS', 
      payload: data 
    });
  } catch (error) {
    yield put({ 
      type: 'FETCH_USERS_FAILURE', 
      payload: error.message 
    });
  }
}

// Root saga - слушает actions
function* rootSaga() {
  yield takeEvery('FETCH_USERS_REQUEST', fetchUsersSaga);
}

export default rootSaga;

Ключевые effects в Redux Saga

  • put - отправляет action в store
  • call - вызывает функцию (обычно асинхронную)
  • select - читает значение из state
  • take - слушает определённый action
  • takeEvery - обрабатывает каждый action типа
  • takeLatest - обрабатывает только последний action
  • fork - запускает побочный эффект без блокировки
  • cancel - отменяет запущенный эффект

Продвинутый пример: Отмена операций

import { takeLatest, cancel, fork } from 'redux-saga/effects';

function* handleSearch(action) {
  const searchTask = yield fork(performSearch, action.payload);
  yield take('CANCEL_SEARCH');
  yield cancel(searchTask);
}

function* rootSaga() {
  yield takeLatest('SEARCH', handleSearch);
}

Сравнение: Thunk vs Saga

АспектThunkSaga
Размер~1 KB~15 KB
СложностьПростаяСредняя
Кривая обученияНизкаяВысокая
ТестированиеФункциональноеПосредством эффектов
Отмена операцийСложноВстроенно
Обработка race conditionsТребует ручной работыyield takeLatest
МасштабируемостьНизкаяВысокая
ПопулярностьОчень высокаяСредняя

Комбинирование Middleware

Можно подключить несколько middleware одновременно:

import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import logger from 'redux-logger';

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const store = createStore(
  rootReducer,
  composeEnhancers(
    applyMiddleware(thunk, logger)
  )
);

Современные альтернативы

Redux Toolkit (современный стандарт) предоставляет встроенную поддержку асинхронных операций:

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';

const fetchUsers = createAsyncThunk(
  'users/fetchUsers',
  async () => {
    const response = await fetch('/api/users');
    return response.json();
  }
);

const usersSlice = createSlice({
  name: 'users',
  initialState: { data: [], status: 'idle' },
  extraReducers: (builder) => {
    builder
      .addCase(fetchUsers.pending, (state) => {
        state.status = 'loading';
      })
      .addCase(fetchUsers.fulfilled, (state, action) => {
        state.status = 'idle';
        state.data = action.payload;
      });
  }
});

Итог

  • Redux Thunk - простое решение для небольших проектов, где action creators возвращают функции
  • Redux Saga - мощное решение для сложных асинхронных потоков, использует генераторы
  • Оба подключаются через applyMiddleware() при создании store
  • Современный подход - использовать Redux Toolkit с createAsyncThunk

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