Как Redux Thunk и Redux Saga подключаются к Redux?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Подключение 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
| Аспект | Thunk | Saga |
|---|---|---|
| Размер | ~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
Выбор между ними зависит от сложности приложения и требований к обработке асинхронных операций.