Асинхронные actions¶
Давайте представим синхронное действие:
- Пользователь кликнул на кнопку
- dispatch action
{type: ТИП_ДЕЙСТВИЯ, payload: доп.данные}
- интерфейс обновился
Давайте представим асинхронное действие:
- Пользователь кликнул на кнопку
- dispatch action
{type: ТИП_ДЕЙСТВИЯ_ЗАПРОС}
- запрос выполнился успешно
- dispatch action
{type: ТИП_ДЕЙСТВИЯ_УСПЕШНО, payload: доп.данные}
- запрос выполнился неудачно
- dispatch action
{type: ТИП_ДЕЙСТВИЯ_НЕУДАЧНО, error: true, payload: доп.данные ошибки}
Благодаря такой схеме, в reducer'e мы сможем реализовать подобное:
1 2 3 4 5 6 7 |
|
Как нам известно, действие - это простой объект, который возвращается функцией его создающей (action creator).
Убедимся в этом:
src/actions/PageActions.js
1 2 3 4 5 6 7 8 |
|
Было бы неплохо иметь возможность возвращать не простой объект, а функцию, внутри которой иметь доступ к методу dispatch
, чтобы можно было диспатчить события в момент, когда они совершились. Псевдокод, мог бы выглядеть так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Но вот незадача, actions - это простой объект, и если action creator возвращает не простой объект, а функцию, то это как-то... Подождите! Ведь это именно то, что нам нужно: Если action creator возвращает не простой объект, а функцию - выполни ее, иначе если это простой объект ... тадам, передай дальше. Более того, мы знаем, что в цепочке middleware у нас как раз есть доступный метод dispatch
! И еще бонусом getState
.
Отлично, мы только что поняли, что нам нужен еще один усилитель. Такой усилитель уже написан, причем код его невероятно прост, я даже приведу его здесь:
усилитель: redux-thunk
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Нам остается лишь добавить зависимость в наш проект.
1 |
|
И добавить redux-thunk в цепочку усилителей перед логгером, так как логгер должен быть последним усилителем в цепочке.
1 2 3 4 5 6 7 8 9 |
|
Для практики, предлагаю написать следующее:
- по клику на кнопку с номером года
- меняется год в заголовке
- ниже (где должны быть фото), появляется текст "Загрузка..."
- после удачной загрузки
- убрать текст "Загрузка..."
- отобразить строку "У тебя ХХ фото" (зависит, от длины массива, переданного в
action.payload
)
вместо реального метода загрузки, будем использовать setTimeout
, который является удобным для тренировок исполнения асинхронных запросов.
Вы можете попробовать выполнить это задание сами, а потом сравнить его с решением ниже.
Для отображения / скрытия фразы "Загрузка...", используйте в reducer'е еще одно свойство у состояния. Например, isFetching
:
1 2 3 4 5 |
|
Решение ниже.
Изменим action creator: src/actions/PageActions.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Изменим reducer: src/reducers/page.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
У нас готова логика для обновления состояния (и интерфейса, разумеется). Осталось поправить отображение.
Так как мы переписали и переименовали функцию (setYear
-> getPhotos
):
src/containers/App.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
|
Обновим соответствующий компонент:
src/components/Page.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
|
Когда будете проверять работу в браузере, обратите внимание на логгер. Он все так же работает и информативен.
Пока мы писали код для асинхронного запроса, мы НЕ нарушили главные принципы redux-приложения:
- Мы всегда возвращали новое состояние (новый объект, смотрите
src/reducers/page.js
) - Мы строго следовали однонаправленному потоку данных в приложении: юзер кликнул - возникло действие - редьюсер изменил - компонент отобразил.
Итого: вы можете сами дописать наше приложение, чтобы оно взаимодействовало с VK, так как все что нужно, это добавить реальный асинхронный запрос (точнее парочку - для логина, и для получения фото). Для этого придется почитать документацию по работе с VK API.
Для тех, кто хочет добить пример поскорее - следующая глава, в которой мы загрузим таки реальные фото из вашего профиля VK.
Исходный код на данный момент.