Асинхронные запросы
Last updated
Last updated
Нам все еще не нужен redux, ничего подобного.
CRA так устроен, что если вы положите что-нибудь в public директорию, это будет доступно по пути:
Переместим наш json с новостями в src/public/data/newsData.json
Теперь его можно открыть GET-запросом на localhost:3000/data/newsData.json
Конечно, при этом у нас сломался импорт в App.js (так как такого файла по старому пути нет):
Так как у нас есть доступ к файлу через GET-запрос, мы можем запросить его.
"Давайте представим задачу" (c)
У нас есть данные на сервере (новости в json), нам нужно их запросить и отобразить в списке. Пока запрос выполняется, мы хотим показывать юзеру надпись: "Загружаю..." вместо списка новостей, чтобы он не нервничал. Когда новости загружены - мы хотим отобразить их как раньше.
Что нового в этой задаче:
как сделать асинхронный запрос (вопрос не про react) [1];
где делать асинхронный запрос (про react) [2];
[1] - это вопрос про нативный js. Запрос будем делать с помощью fetch.
[2] - запрос за данными следует начать в componentDidMount
Начнем с подготовки "состояния" и шаблона.
src/App.js
В данный момент наше приложение не работает, но мы приготовили несколько важных вещей:
во-первых, мы сможем на основе данных в newsData сказать:
если newsData: null
:
если isLoading: false
- значит данные еще не были загружены или произошла ошибка;
если isLoading: true
- данные еще загружаются
если newsData: []
(пустой массив) - значит новостей нет;
если `newsData: [данные про новости] - значит новости есть и они загружены;
В реакт-приложениях, все начинается с представления (описания) данных. Рисуйте в голове или на листочке, так как на основе такой шпаргалки, нам не составит труда сделать шаблон.
Начнем с составления выражений для шаблона. Первое:
То есть мы проверяем, если в this.state.news
- массив - то рисуй компонент новости, он уже умеет рисовать "новостей нет" или список новостей.
Документация про isArray (MDN)
Второе условие:
Оформим все это в компоненте:
src/App.js
Осталось сделать асинхронный вызов и установить правильное состояние.
Помните, мы с вами один раз описали, что количество новостей отображает цифры в зависимости от данных и когда стали добавлять новости - мы это место вообще не трогали, но счетчик работал корректно. Это декларативный подход. Так же и сейчас - мы в силу того, что я вижу всю картину, описали шаблон и как ему себя вести, а состояние разруливать будем на последнем шаге. Такой трюк может быть недоступен вам некоторое время, пока вы обучаетесь, поэтому пишите код как будет удобно, например делайте шаг за шагом что-то и воюйте с ошибками, главное - практика.
Вернемся к коду и сделаем fetch-запрос + console.log'и. Как я уже говорил, запрос за данными будем делать в момент, когда компонент уже примонтирован (то есть появился на странице, то есть нам нужен метод жизненного цикла - componentDidMount):
src/App.js
Посмотрите в network, все работает:
Заглянем в console, и увидим, что так как мы используем стрелочные функции - мы не потеряли this
.
Рассказывать про то как работает promise я не буду, но если у вас есть вопросы, вот мои любимые материалы:
Promise (Кантор)
У нас проблемы с промисами (перевод статьи на хабре)
Урок подходит к логическому завершению. Осталось лишь корректно обновлять состояние компонента.
Задача: до запроса - сделать isLoading: true, после завершения запроса - обновить isLoading: false
, и в news
положить данные, пришедшие с сервера.
(так как решение в пару строк, я сделаю отступ. Очень хочу чтобы вы попробовали сами)
. . . . . .
Решение:
src/App.js
Что интересно, у нас опять все работает. Мы не трогали компонент <News />
, так как мы вновь просто изменили "источник данных".
Так как запрос за данными происходит на localhost, данные прилетают мнгновенно. Давайте искусственно затормозим этот момент, чтобы увидеть как они "загружаются". Добавим таймаут, конечно же.
src/App.js
Подождите три секунды и увидите как появится список новостей. Причем, что хочется отметить - опять нам помогает React. Изменился state -> вызвался render. Никаких дополнительных манипуляций ;)
И никакого Redux/Mobx и прочего. Задача решена без "дичи" в виде кучи библиотек, которые здесь не уместны. Поздравляю.
Итого: научились выполнять асинхронные запросы и показывать прелоадер.