Асинхронный Redux без Middlewares - используем ES2017

Перевод статьи Asynchronous Redux Without Middlewares — Using ES2017
Можно ли обрабатывать асинхронные redux actions без middlewares, а с ES2017 async/await? Мы можем сделать это более понятным способом.
Должен ли я это делать?
Я здесь не для того, чтобы говорить, что вы не должны использовать thunk или saga. Если вы предпочитаете, вы можете представить что это упражнение, которое поможет нам углубить наши знания о redux и функциональном программировании. Кроме того, мы собираемся сделать все это тестируемым.
Проект
Мы собираемся создать простой React проект для использования GitHub API для поиска в репозиториях по имени пользователя. Если вы хотите посмотреть на конечный продукт, перейдите по ссылке ниже:
https://async-redux-without-middleware.herokuapp.com
Давайте покодим
Мы собираемся использовать create-react-app CLI:
npx create-react-app async-redux-without-middlewares
cd async-redux-without-middlewares
Давайте также установим зависимости
npm install -s redux react-redux axios
Http сервис
Создадим сервисы для отделения http-запросов от бизнес-логики. Кроме того, мы собираемся добавить слой абстракции, экспортируя не объект сервиса, а функцию, которая генерирует объект сервиса. Это позволит нам изолировать зависимость axios, что поможет нам тестировать сервис без необходимости фактического вызова http-запросов.
services/repos.js
Action
actions/repos.js
Экспортируемая функция getReposByUsernameInjector
будет использоваться для connect() нашего основного контейнера. На него не будут ссылаться, но после выполнения результат станет свойством компонента.
Получение всех зависимостей getReposByUsername
в виде параметров изолирует функцию, что позволяет нам писать тесты без необходимости импорта стора или фактического вызова нашего сервиса.
Connecting
В react контейнеры - это компоненты, которые подключаются к redux state. Мы собираемся отделить connection от самого компонента.
components/Main.js
containers/ConnectedMain.js
Второй параметр connect() - это вызываемая функция mapDispatchToProps, которая позволяет вам создавать функции, которые диспатчатся при вызове и передают свойства результирующего объекта как props вашему компоненту.
Если вы хотите узнать больше о actions dispatching, я настоятельно рекомендую прочитать эту страницу из документации по redux.
https://react-redux.js.org/using-react-redux/connect-mapdispatch
После подключения все это выглядит так:
Как это тестировать?
Сервис
Чтобы протестировать наш сервис, нам просто нужно вызвать пользовательский объект как axios и ожидать, что get() функция вызовется с URL-адресом репозитория.
services/repos.test.js
The action
Чтобы проверить наши действия, мы настроим пользовательский dispatch() и сервис для имитации четырех возможностей: успешно, пустые репозитории, имя пользователя не найдено и ошибка подключения.
actions/repos.test.js
Контейнер
Поскольку мы отделяем наш connection контейнер от компонента, его проще протестировать отдельно.
Другие компоненты
В проекте намного больше файлов чем описано тут, но они вне контекста данной статьи. Это простая реализация базового React приложения. Если вы хотите узнать больше подробностей, вот GitHub репозиторий:
https://github.com/andregardi/async-redux-without-middlewares
Примечание. Я добавил в окончательный проект @material-ui/core и @material-ui/icons для визуальных компонентов, и express для размещения статических серверов на Heroku.
Присоединяйтесь к нашим каналам FrontEndDev и Web Stack в Telegram, чтобы не пропустить самое интересное из мира Web!