Объясните, как работает Redux Thunk или Redux Saga.

Redux Thunk и Redux Saga — это middleware-библиотеки для Redux, предназначенные для работы с асинхронной логикой, такой как запросы к серверу, таймеры, чтение из локального хранилища и прочее. Они внедряются между dispatch() и редьюсерами, позволяя перехватывать actions и выполнять побочные эффекты до изменения состояния.

Обе библиотеки решают одну и ту же задачу — управление сайд-эффектами, но делают это по-разному.

Redux Thunk

Redux Thunk — это простое middleware, позволяющее dispatch-ить не только обычные объекты (actions), но и функции. Эти функции могут быть асинхронными, обращаться к серверу и по завершении выполнения отправлять другие actions.

Как работает Redux Thunk

  • Если в dispatch() передаётся функция, Redux Thunk перехватывает её.

  • Внутри этой функции можно выполнять асинхронную логику и вызывать dispatch() снова, когда получены данные.

  • Также доступна функция getState() для получения текущего состояния стора.

Пример подключения:

import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
const store = createStore(rootReducer, applyMiddleware(thunk));

Пример асинхронного thunk-действия:

const fetchUser = (userId) => {
return async (dispatch, getState) => {
dispatch({ type: 'FETCH_USER_START' });
try {
const response = await fetch(\`https://api.example.com/users/${userId}\`);
const data = await response.json();
dispatch({ type: 'FETCH_USER_SUCCESS', payload: data });
} catch (error) {
dispatch({ type: 'FETCH_USER_ERROR', error });
}
};
};

В компоненте:

dispatch(fetchUser(1));

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

  • Прост в понимании и применении

  • Подходит для небольших и средних приложений

  • Легко отлаживается и тестируется

Ограничения:

  • Логика разбросана по thunk-функциям

  • Нет формальной структуры

  • Сложно организовать последовательность зависимых задач

  • Неудобно обрабатывать отмену, параллельные операции и ретрай

Redux Saga

Redux Saga использует генераторы (функции-итераторы function*) для описания асинхронной логики. Это middleware, основанное на паттерне "sagas" (вдохновлённом концепцией из DDD), которое перехватывает actions, реагирует на них, выполняет побочные эффекты и может управлять их потоком, откладывать, отменять, обрабатывать параллельно и т. д.

Как работает Redux Saga

  • Вы создаёте "saga" — генератор-функцию, которая описывает побочные эффекты.

  • Используются эффекты (call, put, take, delay, fork, cancel и др.), чтобы управлять логикой.

  • Redux Saga подключается к store и запускает sagaMiddleware.run(rootSaga).

Пример подключения:

import createSagaMiddleware from 'redux-saga';
import { configureStore } from '@reduxjs/toolkit';
const sagaMiddleware = createSagaMiddleware();
const store = configureStore({
reducer: rootReducer,
middleware: \[sagaMiddleware\],
});
sagaMiddleware.run(rootSaga);

Пример простой саги:

import { call, put, takeLatest } from 'redux-saga/effects';
function\* fetchUser(action) {
try {
const response = yield call(fetch, \`https://api.example.com/users/${action.payload}\`);
const data = yield call(\[response, 'json'\]);
yield put({ type: 'FETCH_USER_SUCCESS', payload: data });
} catch (error) {
yield put({ type: 'FETCH_USER_ERROR', error });
}
}
function\* watchFetchUser() {
yield takeLatest('FETCH_USER_REQUEST', fetchUser);
}

В компоненте:

dispatch({ type: 'FETCH_USER_REQUEST', payload: 1 });

Основные эффекты в Redux Saga:

  • take(actionType) — ожидает, пока произойдёт action

  • takeLatest(actionType, worker) — запускает worker-функцию, отменяя предыдущие вызовы

  • call(fn, ...args) — вызывает функцию (например, fetch)

  • put(action) — отправляет action в store

  • delay(ms) — задержка

  • fork(fn) — параллельный вызов (не блокирующий)

  • cancel(task) — отмена задачи

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

  • Высокая гибкость: параллелизм, отмена, дебаунс, throttle и т.д.

  • Подходит для сложных сценариев (чаты, опросы, фоновые операции)

  • Легче тестировать (генераторы можно прогонять по шагам)

  • Разделение побочной логики и UI

Ограничения:

  • Порог входа выше: генераторы, yield, эффекты

  • Сложнее отлаживать, особенно для начинающих

  • Больше шаблонного кода по сравнению с Thunk

Сравнение Redux Thunk и Redux Saga

Характеристика Redux Thunk Redux Saga
Подход Асинхронные функции Генераторы и эффекты
--- --- ---
Простота Проще, менее шаблонного кода Сложнее, но мощнее
--- --- ---
Уровень абстракции Низкий Средний / высокий
--- --- ---
Поддержка отмены задач Требует вручную Есть встроенно (cancel, takeLatest)
--- --- ---
Логика потоков Линейная, последовательная Управление потоками, параллельность
--- --- ---
Тестируемость Умеренная Отличная (можно тестировать генераторы)
--- --- ---
Подходит для Простых асинхронных вызовов Сложной логики, фоновых операций, контроля
--- --- ---

Обе библиотеки могут использоваться в React Native и React-проектах. Redux Thunk чаще применяют в небольших проектах и при простой логике. Redux Saga больше подходит для крупных приложений с множеством зависимых и параллельных операций. Выбор между ними зависит от архитектуры, команды, масштабов и целей проекта.