Статьи

Введение в вызовы API с помощью React и Axios

Из этого туториала вы узнаете, как использовать Axios для извлечения данных, а затем, как манипулировать ими и, в конечном итоге, отображать их на своей странице с функцией фильтрации. Вы узнаете, как пользоваться картой, фильтровать и включать методы по пути. Кроме того, вы будете создавать компонент высшего порядка (HOC) для обработки состояния загрузки выбранных данных из конечной точки API.

Давайте начнем с чистого приложения React. Я предполагаю, что вы используете create-react-app , и имена файлов будут в соответствии с его выводами.

Нам нужно только установить модуль Axios для этого урока.

Перейдите в каталог вашего проекта через окно терминала и введите npm install axios -save , чтобы установить Axios для вашего проекта локально.

Мы будем использовать API генератора случайных пользователей для получения информации о случайных пользователях для использования в нашем приложении.

Давайте добавим модуль App.js в наше приложение, импортировав его в наш файл App.js

1
import axios from ‘axios’

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

Мы хотим получить десять разных пользователей, и нам нужны только имя, фамилия и уникальный идентификатор, который требуется для React при создании списков элементов. Также, чтобы сделать вызов немного более конкретным, давайте включим в качестве примера опцию национальности.

Ниже приведен API, к которому мы будем обращаться.

Обратите внимание, что я не использовал опцию id предоставленную в API, из-за того, что иногда для некоторых пользователей она возвращает null . Итак, просто чтобы убедиться, что для каждого пользователя будет уникальное значение, я включил registered опцию в API.

https://randomuser.me/api/?results=10&inc=name,registered&nat=fr

Вы можете скопировать и вставить его в свой браузер, и вы увидите возвращенные данные в формате JSON.

Теперь, следующая вещь, это сделать вызов API через Axios.

Прежде всего, давайте создадим состояние, чтобы мы могли хранить извлеченные данные.

Внутри нашего компонента App добавьте конструктор класса, а затем создайте состояние.

1
2
3
4
5
6
7
constructor(props){
   super(props)
   this.state = {
     users: [],
     store: []
   }
 }

Здесь вы видите users и состояние store . Один будет использоваться для целей фильтрации и не будет редактироваться, а другой будет содержать результаты фильтрации, которые будут показаны в DOM.

Теперь давайте создадим хук жизненного цикла componentDidMount() .

Внутри этого хука жизненного цикла мы будем извлекать данные, а затем, используя метод map , создадим новые промежуточные данные, которые мы будем использовать внутри метода setState .

Если вы проверите результат вызова API в своем браузере, вы увидите, что в объекте имени есть первая и последняя пары ключ-значение, но нет пары ключ-значение для полного имени. Таким образом, мы будем объединять первое и последнее, чтобы создать полное имя внутри нового объекта JavaScript. Обратите внимание, что JSON и JavaScript Object — разные вещи, хотя в основном они работают одинаково.

Давайте двигаться шаг за шагом.

Добавьте следующий код в компонент App .

1
2
3
4
componentDidMount(){
  axios.get(‘https://randomuser.me/api/?results=10&inc=name,registered&nat=fr’)
  .then(json => console.log(json))
}

Когда вы проверите консоль, вы увидите вывод объекта. Если вы откроете этот объект, внутри него появится другой объект с именем data , а внутри data — массив с именем results .

Давайте далее изменим console.log(json) .

1
2
3
4
componentDidMount(){
  axios.get(‘https://randomuser.me/api/?results=10&inc=name,registered&nat=fr’)
  .then(json => console.log(json.data.results[0].name.first))
}

Здесь мы достигли имени первого значения в массиве результатов.

Теперь давайте воспользуемся встроенным в JavaScript методом map чтобы выполнить итерацию каждого элемента в массиве и создать новый массив объектов JavaScript с новой структурой.

1
2
3
4
5
6
7
8
9
componentDidMount(){
  axios.get(‘https://randomuser.me/api/?results=10&inc=name,registered&nat=fr’)
  .then(json => json.data.results.map(result => (
    {
      name: `${result.name.first} ${result.name.last}`,
      id: result.registered
    })))
  .then(newData => console.log(newData))
}

Здесь мы вызвали метод map для json.data.results , который является массивом, а затем сослались на каждый элемент массива как на result (обратите внимание на разницу в единственном / множественном числе). Затем, используя пару ключ-значение каждого объекта в массиве, мы создали еще один объект с парами ключ-значение name и id .

В конце мы использовали другой метод then , чтобы иметь возможность ссылаться на наши новые данные. Мы назвали его как newData , а затем просто вошли в консоль, чтобы увидеть, все ли прошло как запланировано.

Вы должны увидеть новый массив с объектами, имеющими пары name и id .

Вместо записи результата на консоль, мы должны сохранить его. Для этого мы будем использовать setState .

01
02
03
04
05
06
07
08
09
10
componentDidMount(){
  axios.get(‘https://randomuser.me/api/?results=10&inc=name,registered&nat=fr’)
  .then(json => json.data.results.map(result => (
    {
      name: `${result.name.first} ${result.name.last}`,
      id: result.registered
    })))
  .then(newData => this.setState({users: newData, store: newData}))
  .catch(error => alert(error))
}

Здесь мы изначально устанавливаем users и store данные с нашим новым массивом newData .

Нам нужны две переменные из-за того, что нам нужно хранить исходные данные и никогда не потерять их. Используя информацию в состоянии store , мы можем отфильтровать данные, а затем заполнить состояние users и показать их на странице. Это будет понятнее, когда мы реализуем функцию фильтрации.

И последнее, но не менее важное: мы добавили функцию catch чтобы фактически перехватывать любые возможные ошибки во время выборки и отображать ошибку в виде предупреждающего сообщения.

Идея фильтрации довольно проста. У нас есть состояние store , и оно всегда сохраняет исходные данные без изменений. Затем, используя функцию filter для этого состояния, мы только получаем соответствующие элементы и затем назначаем их состоянию users .

1
this.state.store.filter(item => item.name.toLowerCase().includes(e.target.value.toLowerCase()))

Метод filter требует функции в качестве аргумента, функцию, которая должна быть запущена для каждого элемента в массиве. Здесь мы называем каждый элемент в массиве как item . Затем мы берем ключ имени каждого item и преобразуем его в нижний регистр, чтобы сделать нашу функцию фильтрации нечувствительной к регистру.

После того, как у нас есть ключ name для item , мы проверяем, включает ли он в себя строку поиска, которую мы ввели. includes — это еще один встроенный метод JavaScript. Мы передаем строку поиска, введенную в поле ввода, в качестве аргумента для includes , и она возвращает, если эта строка включена в переменную, для которой она была вызвана. Опять же, мы конвертируем входную строку в нижний регистр, чтобы не имело значения, вводите ли вы строчные или прописные буквы.

В конце метод filter возвращает соответствующие элементы. Поэтому мы просто берем эти элементы и сохраняем их в состоянии users через setState .

Ниже вы можете найти окончательную версию функции, которую мы создали.

1
2
3
filterNames(e){
  this.setState({users: this.state.store.filter(item => item.name.toLowerCase().includes(e.target.value.toLowerCase()))})
}

Хотя для этого небольшого примера мы могли бы поместить все внутри компонента App , давайте воспользуемся преимуществами React и создадим несколько небольших функциональных компонентов / компонентов без состояния.

Давайте добавим следующую структуру в метод render компонента App .

01
02
03
04
05
06
07
08
09
10
render() {
  const {users} = this.state
  return (
    <div className=»Card»>
      <div className=»header»>NAME LIST</div>
      <SearchBar searchFunc={(e) => this.filterNames(e)}/>
      <List usernames={users}/>
    </div>
  );
}

В настоящее время мы сосредоточимся только на функциональности. Позже я предоставлю созданный мной файл CSS.

Обратите внимание, что у нас есть реквизиты searchFunc для компонента SearchBar и реквизиты usernames для компонента List .

Обратите внимание, что мы используем состояние users вместо состояния store для отображения данных, потому что это состояние users содержащее отфильтрованные результаты.

Этот компонент довольно прост. Он принимает функцию filterNames в качестве реквизита и вызывает эту функцию при изменении поля ввода.

01
02
03
04
05
06
07
08
09
10
11
import React from ‘react’
 
const SearchBar = props => {
  return(
    <div>
      <input className=»searchBar» type=»text» placeholder=»search user» onChange={props.searchFunc}/>
    </div>
  )
}
 
export default SearchBar

Этот просто перечислит имена пользователей.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
import React, {Component} from ‘react’
import LoadingHOC from ‘./LoadingHOC’
import ‘../styles/main.css’
 
const List = (props) =>{
  const{usernames} = props
  return(
    <ul>
      {usernames.map(user => <li key={user.id}>{user.name}</li>)}
    </ul>
  )
}
 
export default LoadingHOC(List)

Здесь мы снова использовали метод map чтобы получить каждый элемент в массиве и создать из него элемент <li> . Обратите внимание, что когда вы используете map для создания списка элементов, вам нужно использовать key чтобы React отслеживал каждый элемент списка.

Обратите внимание, что мы обернули List другим компонентом с именем LoadingHOC перед его экспортом. Вот как работают компоненты высшего порядка (HOC).

Здесь мы передали наш компонент в качестве аргумента другому компоненту перед его экспортом. Таким образом, этот компонент LoadingHOC будет LoadingHOC наш компонент новыми функциями.

Как я кратко объяснил ранее, HOC принимает компонент в качестве входных данных, а затем экспортирует расширенную версию входного компонента.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
import React, {Component} from ‘react’
import spinner from ‘../spinner.gif’
 
const LoadingHOC = (WrappedState) =>{
  return(
    class LoadingHOC extends Component{
      render(){
        return this.props.usernames.length === 0 ?
      }
    }
  )
}
 
export default LoadingHOC

Внутри HOC мы можем получить прямой доступ к реквизиту входного компонента. Поэтому мы просто проверяем, равна ли длина имени usernames prop 0 или нет. Если оно равно 0 , это означает, что данные еще не получены, поскольку по умолчанию это пустой массив. Таким образом, мы просто показываем GIF с блесной, который мы импортировали В противном случае мы просто показываем сам компонент ввода.

Он импортирован, чтобы не забыть передать любые реквизиты и состояния обратно компоненту ввода с помощью оператора распространения. В противном случае ваш компонент будет лишен их.

Ниже вы можете найти файл CSS, характерный для этого примера.

01
02
03
04
05
06
07
08
09
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
body, html {
  -webkit-font-smoothing: antialiased;
  margin: 0;
  padding: 0;
  background-color: #f1f1f1;
  font-family: ‘Raleway’, sans-serif;
  -webkit-text-size-adjust: 100%;
}
 
body {
  display: flex;
  justify-content: center;
  font-size: 1rem/16;
  margin-top: 50px;
}
 
li, ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
 
ul {
  margin-top: 10px;
}
 
li {
  font-size: 0.8rem;
  margin-bottom: 8px;
  text-align: center;
  color: #959595;
}
 
li:last-of-type {
  margin-bottom: 50px;
}
 
.Card {
  font-size: 1.5rem;
  font-weight: bold;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 200px;
  border-radius: 10px;
  background-color: white;
  box-shadow: 0 5px 3px 0 #ebebeb;
}
 
.header {
  position: relative;
  font-size: 20px;
  margin: 12px 0;
  color: #575757;
}
 
.header::after {
  content: »;
  position: absolute;
  left: -50%;
  bottom: -10px;
  width: 200%;
  height: 1px;
  background-color: #f1f1f1;
}
 
.searchBar {
  text-align: center;
  margin: 5px 0;
  border: 1px solid #c4c4c4;
  height: 20px;
  color: #575757;
  border-radius: 3px;
}
 
.searchBar:focus {
  outline-width: 0;
}
 
.searchBar::placeholder {
  color: #dadada;
}
 
.isLoading {
  margin: 30px 0;
  width: 150px;
  filter: opacity(0.3);
}

В этом уроке мы кратко рассмотрели API генератора случайных пользователей как источник случайных данных. Затем мы извлекли данные из конечной точки API и реструктурировали результаты в новом объекте JavaScript с помощью метода map .

Следующим шагом было создание функции фильтрации с помощью filter и методов. Наконец, мы создали два разных компонента и усовершенствовали один из них компонентом высшего порядка (HOC), введя индикатор загрузки, когда данных еще нет.

За последние пару лет популярность React возросла. На самом деле, у нас есть ряд товаров на Envato Market, которые можно приобрести, просмотреть, внедрить и так далее. Если вы ищете дополнительные ресурсы по React, не стесняйтесь проверить их .