Асинхронный Redux
2. Асинхронные действия
Redux не предоставляет функционала для отправки асинхронных действий, эту задачу решают прослойки. Есть много готовых решений: для простых асинхронных операций подойдет redux-promise
, для средней сложности redux-thunk
, а для очень сложных и запутанных redux-saga
или redux-observable
.
Для начала необходимо научиться писать асинхронные action creators
. Это функции которые вместо объекта-действия возвращают функцию. В компьютерных науках это называется thunk
.
const asyncActionCreator = args => dispatch => {};
Когда action creator
возвращает функцию, эта функция будет выполняться прослойкой. Такая функция не должна быть чистой, поэтому она может иметь побочные эффекты, в том числе выполнение асинхронных HTTP-запросов. В ее теле также могут быть отправлены другие сихронные действия.
const asyncActionCreator = args => dispatch => {
fetch('some url')
.then(r => r.json())
.then(data => {
dispatch({
type: 'FETCH_SUCCESS',
payload: data,
});
});
};
2.1. thunk middleware
Напишем прослойку thunk
, которая умеет обрабатывать асинхронные действия. Если действие это функция, она будет вызвана и аргументами ей будут переданы dispatch
и getState
, тем самым позволяя использовать dispatch
в теле действия. В противном случае, если это обычный объект, действие будет отправлено дальше по цепочке прослоек.
const thunk = ({ dispatch, getState }) => next => action =>
typeof action === 'function' ? action(dispatch, getState) : next(action);
2.2. HTTP-запросы
При асинхроннах операциях зачастую необходимо отображать лоадеры и обрабатывать ошибки. В таких случаях можно использовать следующую схему действий.
Начальное состояние может выглядеть так, с полями флага загрузки и хранения ошибки.
{
notes: {
items: [],
loading: false,
error: null
}
}
Copy
Тогда асинхронное действие может выглядеть так.
При
notes/FETCH_START
в полеloading
записываетсяtrue
, а приnotes/FETCH_SUCCESS
илиnotes/FETCH_FAILURE
наоборотfalse
При
notes/FETCH_FAILURE
в полеerror
записывается объект ошибкиПри
notes/FETCH_SUCCESS
в полеitems
записываются данные
const fetchStart = () => ({
type: 'notes/FETCH_START',
});
const fetchSuccess = data => ({
type: 'notes/FETCH_SUCCESS',
payload: data,
});
const fetchFailure = error => ({
type: 'notes/FETCH_FAILURE',
payload: error,
});
const asyncActionCreator = args => dispatch => {
dispatch(fetchStart());
fetch('some url')
.then(r => r.json())
.then(data => dispatch(fetchSuccess(data)))
.catch(err => dispatch(fetchFailure(err)));
};
Copy
2.3. Дополнительные материалы
Last updated
Was this helpful?