Продолжая два моих предыдущих блога о Redux, Понимание Redux и Реализация Redux в React, мы получили представление о рабочем процессе Redux и о том, как он реализован в приложении React. Однако до этого момента мы видели только то, как выполняются синхронные задачи. Итак, нам нужен способ обработки операций ввода-вывода, таких как доступ к базе данных или API, и, к счастью, есть библиотека, которая помогает в этом. Библиотека называется Redux Thunk и предоставляет доступ к промежуточному программному обеспечению, которое встраивается в рабочий процесс Redux. Промежуточное программное обеспечение — это функции, которые внедряются между установленными процессами для выполнения их логики и только после этого позволяют продолжить процесс в обычном режиме. Итак, чтобы привести пример, базовый рабочий процесс для Redux состоит в том, чтобы функция диспетчеризации отправляла объект действия, который затем принимался функцией редуктора, которая использует информацию в действии для соответствующего обновления глобального состояния. С промежуточным ПО и в случае с Redux Thunk вместо отправки объекта действия функция отправки отправляет и выполняет промежуточное ПО thunk. Промежуточное ПО, которое снова является функцией, имеет доступ к диспетчерской функции, которую оно может использовать для выполнения своих собственных диспетчерских операций редюсеру. После того, как промежуточное программное обеспечение выполнит свою логику, оно затем отправляет действие, которое принимает редьюсер, как обычно. Как видите, промежуточное ПО вмешивается в обычный процесс Redux, и таким образом обрабатывается асинхронный код. По сути, промежуточное ПО останавливает процесс до тех пор, пока не будет решена какая-то асинхронная задача, а затем возобновляет процесс.

Чтобы проиллюстрировать это и реализацию, мы начнем с установки библиотеки thunk:

npm install --save redux-thunk

После этого глобальное состояние Redux требует дополнительной настройки для включения промежуточного программного обеспечения. В файле index.js, где Redux импортируется и настраивается, функция «applyMiddleware» также будет импортирована вместе с функцией «createStore», которая позволяет создавать глобальное состояние и использовать промежуточное ПО в рабочем процессе.

// index.js
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from // some file path 
const store = createStore(rootReducer, applyMiddleware(thunk));

После этой настройки мы обращаем наше внимание на написание логики, которая будет выполняться функцией диспетчеризации. Обычно функция отправки отправляет объект действия в редуктор, но на этот раз она выполнит промежуточное ПО thunk. Поскольку сложность рабочего процесса увеличивается, и действие больше не будет отправляться напрямую, рекомендуется разместить всю логику действий в отдельном файле. Так:

// actions/actions.js
// thunk middleware
export const someFunc = () => {
  return dispatch => {
    getData(dispatch);
  };
};
const getData = async(dispatch) => {
  try {
    const response = await fetch(url);
    const data = await response.json();
    
    dispatch({ type: 'SOME_ACTION', data });
  } catch (error) {
    dispatch({ type: 'ERROR_ACTION', error });
  }
};

Давайте разберем код выше. Во-первых, у нас есть промежуточное ПО thunk, которое представляет собой функцию «someFunc», которая возвращает анонимную функцию, которая имеет доступ к функции отправки в качестве аргумента. Затем возвращаемая функция может передать функцию отправки в качестве аргумента создателю действия, который является функцией, возвращающей объект действия, в данном случае «asyncFunc». Затем мы определяем создателя действия как асинхронную функцию, которая получает функцию отправки и выполняет асинхронную задачу. После решения асинхронной задачи он продолжает рабочий процесс Redux по отправке фактического объекта действия редуктору для обновления глобального состояния. И, как вы можете видеть, в зависимости от результата промиса, либо полученные данные будут переданы как полезная нагрузка, либо как ошибка.

Приведенный выше пример также имитирует распространенную ситуацию, когда компоненту после монтирования необходимо получить данные из API и сохранить их в глобальном состоянии. Как только создатель асинхронного действия получает или не может получить данные, он отправляет результат в виде полезной нагрузки, где он будет храниться в глобальном состоянии. Чтобы еще больше проиллюстрировать это:

// someComponent.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import someFunc from // file path to actions.js
class someComponent extends Component {
  componentDidMount() {
    this.props.onInitData();
  }
  render() {
    return <div>{this.props.someData}</div>;
  }
}
const mapStateToProps = state => {
  return {
    someData: state.data
  };
};
const mapDispatchToProps = dispatch => {
  return {
   onInitData: () => dispatch(someFunc())
  };
};
export connect(mapStateToProps, mapDispatchToProps)(someComponent);

Итак, собрав все вместе, компонент, который теперь подключен или подписан на глобальное состояние, имеет доступ к информации, хранящейся в глобальном состоянии, и функциям отправки, которые позволят ему инициировать событие обновления с помощью двух функций mapStateToProps и mapDispatchToProps. Кроме того, промежуточное ПО импортируется, а затем передается аргумент функции отправки вместо традиционного объекта действия. При монтировании этого компонента он выполнит функцию «onInitData», которая была названа произвольно, и, что более важно, она сопоставляется с функцией диспетчеризации, которая выполняет промежуточное программное обеспечение.

Следуя этому шаблону, асинхронный код можно привести в соответствие с синхронным и унифицированным рабочим процессом Redux. В дополнение к функции отправки промежуточное ПО thunk также предоставляет доступ к глобальному состоянию через функцию «getState». Эту функцию можно использовать для доступа к любым данным, хранящимся в глобальном состоянии, которые могут потребоваться при обновлении глобального состояния определенным образом.

// actions/actions.js
// thunk middleware
export const someFunc = () => {
  return dispatch, getState => {
    const { someProp } = getState();
    getData(dispatch, someProp);
  };
};

В этом примере вы можете увидеть функцию getState, которая используется для доступа к некоторому свойству в глобальном состоянии посредством деструктуризации. Затем эти данные могут быть переданы создателю действия для использования каким-либо образом, в конечном итоге при обновлении состояния.

Чтобы узнать больше о библиотеке thunk и обработке асинхронного кода, вы можете просмотреть документы. Также не забудьте просмотреть мои предыдущие статьи, чтобы подвести итоги Redux.