React course
  • Компоненты и коллекции
  • TypeScript
  • Стилизация
  • События и состояния
  • Формы
  • Жизненный цикл
  • Функциональные vs классовые компоненты
  • Основы Redux
  • Redux Toolkit
  • Асинхронный Redux
  • Селекторы
  • React Router
  • Code splitting
  • Паттерны и контекст
  • Анимация
Powered by GitBook
On this page
  • 2. Асинхронные действия
  • 2.1. thunk middleware
  • 2.2. HTTP-запросы
  • 2.3. Дополнительные материалы

Was this helpful?

Асинхронный 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. Дополнительные материалы

PreviousRedux ToolkitNextСелекторы

Last updated 4 years ago

Was this helpful?

Репозиторий redux-thunk
Thunks in Redux: The Basics
Redux Thunk Tricks