Объясните, как работает 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 больше подходит для крупных приложений с множеством зависимых и параллельных операций. Выбор между ними зависит от архитектуры, команды, масштабов и целей проекта.