Асинхронные действия

Без middleware хранилище Redux поддерживает только синхронный поток данных. Это то, что вы получаете по умолчанию с createStore().

Вы можете усилить createStore() с помощью applyMiddleware(). Это не обязательно, но позволяет удобно выражать асинхронные действия.

Асинхронное Middleware, такое как redux-thunk, обертывает метод dispatch() store и позволяет отправлять что-то, кроме действий, например, функции или promises. Любое middleware, которое вы используете, может затем перехватить все, что вы отправляете, и, в свою очередь, может передать действия следующему middleware в цепочке. Например, middleware Promise может перехватывать обещания и асинхронно отправлять пару начальных / конечных actions в ответ на каждое обещание.

Middleware

Redux middleware предоставляет стороннее расширение между отправкой действия и моментом его попадания в reducer. Redux middleware используют для ведения журналов, отчетов о сбоях, взаимодействия с асинхронным API, маршрутизации и многого другого.

Если мы захотим логировать наши экшины,мы можем написать свою middleware. Она может выглядить так:

const logger = (store) => (next) => (action) => {
console.log("dispatching", action);
let result = next(action);
console.log("next state", store.getState());
return result;
};
middleware

Async Actions

Когда вы вызываете асинхронный API, есть два решающих момента времени: момент, когда вы начинаете вызов, и момент, когда вы получаете ответ (или тайм-аут). Каждый из этих двух моментов обычно требует изменения состояния приложения; для этого вам нужно отправить обычные actions, которые будeт обрабатывать reducer синхронно. Обычно для любого запроса API требуется выполнить как минимум три различных типа действий:

  • Action, информирующее reducers о начале запроса.

Reducers могут обрабатывать это действие, переключая флаг isFetching в состоянии. Таким образом пользовательский интерфейс знает, что пора показать spinner.

  • Action, информирующее reducer об успешном завершении запроса.

Reducers могут обрабатывать это действие путем объединения новых данных в состояние, которым они управляют, и сброса isFetching. Пользовательский интерфейс скрывал spinner и отображал полученные данные.

  • Action, информирующее reducer о сбое запроса.

Reducers могут обработать это действие, сбросив isFetching. Кроме того, некоторые редукторы могут захотеть сохранить сообщение об ошибке, чтобы пользовательский интерфейс мог его отобразить.

Вы можете использовать специальное поле status в своих действиях:

{ type: 'FETCH/POSTS/PENDING' } // status = pending
{ type: 'FETCH/POSTS/REJECTED', status: 'rejected', error: 'Oops' }
{ type: 'FETCH/POSTS/RESOLVED', status: 'resolved', response: { ... } }
async actions

Redux Thunk

Зачем мне это нужно? 🤔

С обычным базовым хранилищем Redux мы можем выполнять только простые синхронные обновления, отправляя действие. Middleware расширяет возможности store и позволяет писать асинхронную логику, которая взаимодействует с Redux store.

Thunks- это рекомендуемое промежуточное программное обеспечение для базовой логики побочных эффектов Redux, включая сложную синхронную логику, которая требует доступа к хранилищу, и простую асинхронную логику, такую как запросы AJAX.

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

Action creator, который возвращает функцию для выполнения асинхронной отправки:

const INCREMENT_COUNTER = "INCREMENT_COUNTER";
function increment() {
return {
type: INCREMENT_COUNTER,
};
}
function incrementAsync() {
return (dispatch) => {
setTimeout(() => {
// Yay! Can invoke sync or async actions with `dispatch`
dispatch(increment());
}, 1000);
};
}

Action creator, который возвращает функцию для выполнения условной отправки:

function incrementIfOdd() {
return (dispatch, getState) => {
const { counter } = getState();
if (counter % 2 === 0) {
return;
}
dispatch(increment());
};
}

Action creator с Promise

const actionFetch = () => {
return (dispatch) => {
//возвращаем функцию.
let promise = fetch("/api");
dispatch({ type: "REQUEST/PENDING" });
promise.then(
(data) => dispatch({ type: "REQUEST/RESOLVED", payload: data }),
(error) => dispatch({ type: "REQUEST/REJECTED", error: error })
);
};
};

Action creator с async await

function asyncActionFetch(){
return async function (dispatch){
dispatch({ type: "REQUEST/PENDING" });
try {
const data = await apiRequest()
dispatch({ type: "REQUEST/RESOLVED", payload: data }),
}
catch (error) {
dispatch({ type: "REQUEST/REJECTED", error: error })
}
}
}

Что такое thunk ?!

Thunk - это функция, которая обертывает выражение, чтобы отложить его выполнение.

// вычисление 1 + 2 происходит немедленно
// x === 3
let x = 1 + 2;
// расчет 1 + 2 задерживается
// foo можно вызвать позже, чтобы выполнить расчет
// foo is a thunk!
let foo = () => 1 + 2;
Интересно

Код Redux-Thunk состоит только из 14 строк.

Установка 💻

npm install --save redux-thunk
import thunk from "redux-thunk";
import { createStore, combineReducers, applyMiddleware } from "redux";
const store = createStore(rootReducer, applyMiddleware(thunk));

Практика 👩‍💻👨‍💻

  1. Async Counter

Добавить actions

  • reset
  • decrement
  1. User List

Пользуясь заданием User List, переписать код с использованием Redux.

Почитать 📚

ДЗ 👩‍🎓🧑‍🎓

Используя ДЗ Github users

Переписать с использованием Redux и Redux thunk для асинхронный действий.

Edit this page on GitHub