Подтвердить что ты не робот

Каков правильный способ вызова API в js реакции?

Я недавно перешел из Angular в ReactJ. Я использую jQuery для вызовов API. У меня есть API, который возвращает случайный список пользователей, который должен быть напечатан в списке.

Я не уверен, как писать свои вызовы API. Какова лучшая практика для этого?

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

Ниже мой код:

import React from 'react';

export default class UserList extends React.Component {    
  constructor(props) {
    super(props);
    this.state = {
      person: []
    };
  }

  UserList(){
    return $.getJSON('https://randomuser.me/api/')
    .then(function(data) {
      return data.results;
    });
  }

  render() {
    this.UserList().then(function(res){
      this.state = {person: res};
    });
    return (
      <div id="layout-content" className="layout-content-wrapper">
        <div className="panel-list">
          {this.state.person.map((item, i) =>{
            return(
              <h1>{item.name.first}</h1>
              <span>{item.cell}, {item.email}</span>
            )
          })}
        <div>
      </div>
    )
  }
}
4b9b3361

Ответ 1

В этом случае вы можете выполнить ajax-вызов внутри componentDidMount, а затем обновить state

export default class UserList extends React.Component {
  constructor(props) {
    super(props);

    this.state = {person: []};
  }

  componentDidMount() {
    this.UserList();
  }

  UserList() {
    $.getJSON('https://randomuser.me/api/')
      .then(({ results }) => this.setState({ person: results }));
  }

  render() {
    const persons = this.state.person.map((item, i) => (
      <div>
        <h1>{ item.name.first }</h1>
        <span>{ item.cell }, { item.email }</span>
      </div>
    ));

    return (
      <div id="layout-content" className="layout-content-wrapper">
        <div className="panel-list">{ persons }</div>
      </div>
    );
  }
}

Ответ 2

Вы можете проверить Flux Architecture. Я также рекомендую проверить React-Redux Implementation. Поместите свои вызовы api в свои действия. Он намного чище, чем все это в компоненте.

Действия - это вспомогательные методы, которые вы можете вызвать для изменения состояния приложения или выполнения вызовов api.

Ответ 3

Используйте метод fetch внутри componentDidMount для обновления состояния. как ниже

....

componentDidMount(){
  fetch('https://randomuser.me/api/')
      .then(({ results }) => this.setState({ person: results }));
}

....

Ответ 4

Я бы хотел, чтобы вы взглянули на сокращение http://redux.js.org/index.html

Они имеют очень четко определенный способ обработки асинхронных вызовов, то есть вызовов API, и вместо использования вызовов jQuery для API я бы рекомендовал использовать выборки или запроса npm пакеты выборка в настоящее время поддерживается современными браузерами, но также доступна прокладка для серверной части.

Существует также еще один удивительный пакет superagent, который имеет много вариантов при создании запроса API и его очень легко использовать.

Ответ 5

Это обсуждение было долгим, и @Alexander T. answer предоставил хорошее руководство, чтобы понять, кто новичок, чтобы реагировать, как я. И я поделюсь некоторыми дополнительными ноу-хау о вызове одного и того же API несколько раз для обновления компонента, я думаю, что это, вероятно, распространенная проблема, с которой новичок может столкнуться в начале.

componentWillReceiveProps(nextProps), из официальной документации :

Если вам нужно обновить состояние в ответ на изменения реквизита (для Например, чтобы сбросить его), вы можете сравнить this.props и nextProps и выполнить переходы состояния, используя this.setState() в этом методе.

Можно сделать вывод, что именно здесь мы обрабатываем реквизиты из родительского компонента, выполняем вызов API и обновляем состояние.

Основан на @Alexander T. пример:

export default class UserList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {person: []};
  }

  componentDidMount() {
   //For our first load. 
   this.UserList(this.props.group); //maybe something like "groupOne"
  }

  componentWillReceiveProps(nextProps) {
    // Assuming parameter comes from url.
    // let group = window.location.toString().split("/")[*indexParameterLocated*];
    // this.UserList(group);

    // Assuming parameter comes from props that from parent component.
    let group = nextProps.group; // Maybe something like "groupTwo" 
    this.UserList(group);
  }

  UserList(group) {
    $.getJSON('https://randomuser.me/api/' + group)
      .then(({ results }) => this.setState({ person: results }));
  }

  render() {
    return (...)
  }
}

Обновление

componentWillReceiveProps() устарела.

Вот только некоторые методы (все они в Doc) в жизненном цикле, которые, я думаю, будут связаны с развертыванием API в общем случае: enter image description here

Ссылаясь на диаграмму выше:

  • Развертывание API в componentDidMount()

    Правильный сценарий для вызова API здесь состоит в том, что содержимое (из ответа API) этого компонента будет статичным, componentDidMount() будет срабатывать только один раз, пока компонент монтируется, даже новые реквизиты будут переданы из родительского компонента или будут иметь действия, чтобы вести re-rendering.
    Компонент проверяет разницу для повторного рендеринга, но не для повторного монтирования.
    Цитата из документа:

Если вам нужно загрузить данные из удаленной конечной точки, это хорошее место для создать экземпляр сетевого запроса.


  • Развертывание API в static getDerivedStateFromProps(nextProps, prevState)

Мы должны заметить, что существует два вида обновления компонента, setState() в текущем компоненте would не будет приводить к запуску этого метода, а будет повторно выполнять рендеринг или новый реквизит из родительского компонента сделать. Мы могли бы узнать, что этот метод также срабатывает во время монтажа.

Это подходящее место для развертывания API , если мы хотим использовать текущий компонент как шаблон, а новые параметры для API - это реквизиты, исходящие от родительского компонента.
Мы получаем другой ответ от API и возвращаем новый state здесь, чтобы изменить содержимое этого компонента.

Например:
 У нас есть раскрывающийся список для различных автомобилей в родительском компоненте, этот компонент должен отображать сведения о выбранном.


  • Развертывание API в componentDidUpdate(prevProps, prevState)

В отличие от static getDerivedStateFromProps(), этот метод вызывается сразу после каждого рендеринга, кроме начального рендеринга. Мы могли бы иметь вызов API и визуализировать разницу в одном компоненте.

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

Этот метод действительно может быть использован так же, как static getDerivedStateFromProps() с подпорками, но необходимо обрабатывать изменения props с помощью prevProps. И нам нужно сотрудничать с componentDidMount() для обработки начального вызова API.

Цитата из документа:

... Это также хорошее место для сетевых запросов, если вы сравнить текущие реквизиты с предыдущими реквизитами...

Ответ 6

Функция Render должна быть чистой, это означает, что она использует только состояние и реквизиты для рендеринга, никогда не пытайтесь изменить состояние в рендеринге, это обычно вызывает уродливые ошибки и значительно снижает производительность. Это также хороший момент, если вы отделяете выборку данных и отображаете проблемы в своем приложении React. Я рекомендую вам прочитать эту статью, которая очень хорошо объясняет эту идею. https://medium.com/@learnreact/container-components-c0e67432e005#.sfydn87nm

Ответ 7

Эта часть из документации по React v16 ответит на ваш вопрос, читайте о componentDidMount():

componentDidMount()

componentDidMount() вызывается сразу после монтирования компонента. Инициализация, которая требует DOM-узлов, должна быть здесь. Если вам нужно загрузить данные из удаленной конечной точки, это хорошее место для создания сетевого запроса. Этот метод является хорошим местом для настройки любых подписок. Если вы это сделаете, не забудьте отписаться в componentWillUnmount().

Как вы видите, componentDidMount считается лучшим местом и циклом для выполнения вызова API, а также для доступа к узлу, что означает, что к этому времени безопасно выполнять вызов, обновлять представление или все, что вы можете сделать, когда документ готов, если вы используя jQuery, он должен как-то напоминать вам функцию document.ready(), где вы можете убедиться, что все готово для всего, что вы хотите сделать в своем коде...

Ответ 8

1) Вы можете использовать F etch API для извлечения данных из конечных точек:

Пример выборки всех ответов Github для пользователя

  /* Fetch GitHub Repos */
  fetchData = () => {

       //show progress bar
      this.setState({ isLoading: true });

      //fetch repos
      fetch('https://api.github.com/users/hiteshsahu/repos')
      .then(response => response.json())
      .then(data => {
        if (Array.isArray(data)) {
          console.log(JSON.stringify(data));
          this.setState({ repos: data ,
                         isLoading: false});
        } else {
          this.setState({ repos: [],
                          isLoading: false  
                        });
        }
      });
  };

2) Другая альтернатива - Axios

С помощью axios вы можете вырезать средний шаг прохождения результатов HTTP-запрос к методу .json(). Axios просто возвращает данные объект, который вы ожидаете.

  import axios from "axios";

 /* Fetch GitHub Repos */
  fetchDataWithAxios = () => {

     //show progress bar
      this.setState({ isLoading: true });

      // fetch repos with axios
      axios
          .get('https://api.github.com/users/hiteshsahu/repos')
          .then(result => {
            console.log(result);
            this.setState({
              repos: result.data,
              isLoading: false
            });
          })
          .catch(error =>
            this.setState({
              error,
              isLoading: false
            })
          );
}

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

class App extends React.Component {
  state = {
    repos: [],
   isLoading: false
  };

  componentDidMount() {
    this.fetchData ();
  }

Тем временем вы можете отображать индикатор выполнения во время загрузки данных

   {this.state.isLoading && <LinearProgress />}

Ответ 9

Чистый способ - сделать асинхронный вызов API внутри componentDidMount с помощью функции try/catch.

Когда мы вызываем API, мы получаем ответ. Затем мы применяем метод JSON, чтобы преобразовать ответ в объект JavaScript. Затем мы берем из этого объекта ответа только его дочерний объект с именем "results" (data.results).

В начале мы определили "userList" в состоянии как пустой массив. Как только мы выполняем вызов API и получаем данные из этого API, мы присваиваем "результаты" списку пользователей, используя метод setState.

Внутри функции рендеринга мы говорим, что userList будет приходить из состояния. Поскольку userList - это массив объектов, которые мы отображаем через него, для отображения картинки, имени и номера телефона каждого объекта "пользователь". Чтобы получить эту информацию, мы используем точечную запись (например, user.phone).

ПРИМЕЧАНИЕ: в зависимости от вашего API ваш ответ может выглядеть по-разному. Console.log весь "ответ", чтобы увидеть, какие переменные вам нужны от него, а затем назначить их в setState.

UserList.js

import React, { Component } from "react";

export default class UserList extends Component {
   state = {
      userList: [], // list is empty in the beginning
      error: false
   };

   componentDidMount() {
       this.getUserList(); // function call
   }

   getUserList = async () => {
       try { //try to get data
           const response = await fetch("https://randomuser.me/api/");
           if (response.ok) { // ckeck if status code is 200
               const data = await response.json();
               this.setState({ userList: data.results});
           } else { this.setState({ error: true }) }
       } catch (e) { //code will jump here if there is a network problem
   this.setState({ error: true });
  }
};

  render() {
  const { userList, error } = this.state
      return (
          <div>
            {userList.length > 0 && userList.map(user => (
              <div key={user}>
                  <img src={user.picture.medium} alt="user"/>
                  <div>
                      <div>{user.name.first}{user.name.last}</div>
                      <div>{user.phone}</div>
                      <div>{user.email}</div>
                  </div>
              </div>
            ))}
            {error && <div>Sorry, can not display the data</div>}
          </div>
      )
}}

Ответ 10

Чистый способ - сделать асинхронный вызов API внутри componentDidMount с помощью функции try/catch. Мы используем метод json для ответа, чтобы преобразовать ответ в объект JavaScript. Затем мы берем из этого объекта ответа только объект с именем "results" (data.results). В начале мы определили "userList" в состоянии как пустой массив. Как только мы выполняем вызов API и получаем данные от этого API, мы присваиваем "результаты" userList с помощью метода setState. Внутри функции рендеринга мы говорим, что userList будет приходить из состояния. Поскольку userList - это массив объектов, которые мы отображаем через него, чтобы отобразить картинку, имя и номер телефона каждого объекта "пользователь". Для получения этой информации мы используем точечную запись (например, user.phone). Я применил некоторые стили ниже, это интерфейс: enter image description here

ПРИМЕЧАНИЕ: в зависимости от вашего API ваш ответ может выглядеть по-разному. Console.log весь "ответ", чтобы увидеть, какие переменные вам нужны от него, а затем назначить их в setState. Я сделал видео на ту же тему, где вы можете увидеть пошаговое руководство по асинхронному вызову API.

UserList.js

import React, { Component } from "react";
import "./UserList.css";

export default class UserList extends Component {
  state = {
    userList: [], // list is empty in the beginning
    error: false
  };

  componentDidMount() {
    this.getUserList(); // function call
  }

  getUserList = async () => {
    try { //try to get data
      const response = await fetch("https://randomuser.me/api/");
      if (response.ok) { // ckeck if status code is 200
        const data = await response.json();
        this.setState({ userList: data.results});
      } else { this.setState({ error: true }) }
    } catch (e) { //code will jump here if there is a network problem
      this.setState({ error: true });
    }
  };

  render() {
      const { userList, error } = this.state
      return (
          <div className="list__container">
              {userList.length > 0 && userList.map(user => (
                  <div className="list__item" key={user}>
                      <img src={user.picture.medium} className="list-item__photo" alt="user"/>
                      <div className="list-item__info-wrap">
                          <div className="list-item__name">{user.name.first}{user.name.last}</div>
                          <div className="list-item__phone">{user.phone}</div>
                          <div className="list-item__email">{user.email}</div>
                      </div>
                  </div>
              ))}
              {error && <div>Sorry, can not display the data</div>}
          </div>
      )
  }}

UserList.css

.list__container {
  background: #0f0f0f;
  color: #f2f2f2;
  padding: 30px 0;
  text-align: center;
}
.list__item {
  display: flex;
  align-items: center;
  justify-content: center;
}
.list-item__photo {
  width: 100px;
  height: 100px;
  border-radius: 50%;
}
.list-item__info-wrap {
  margin-left: 20px;
  text-align: left;
}
.list-item__name {
  text-transform: capitalize;
}