який правильний спосіб зробити виклик API у реакції js?


137

Нещодавно я перейшов з кутового до ReactJs. Я використовую 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>
    )
  }
}

2
Я залежить від того, яку бібліотеку управління державою ви використовуєте. Якщо ви не використовуєте жодних, ви можете перемістити свої дзвінки api в окремий файл, а виклик функцій api у вашій ситуації під час componentDidMountзворотного дзвінка.
1вен

Ви можете використовувати fetch()замість jQuery, якщо ви використовуєте jQuery лише для виконання запитів Ajax.
Фред

Навіщо використовувати Jquery? Jquery - це величезна бібліотека, і вона непотрібна
Робін

Просто додамо тут, що зараз useEffect, мабуть, є місцем для виклику api. Дивіться btholt.github.io/complete-intro-to-react-v5/effects
shw

Відповіді:


98

У цьому випадку ви можете здійснити дзвінок 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
Це спрацювало, спасибі. Скажіть, будь ласка, "яка з них найкраща бібліотека для кращого управління державою"
Raj Rj

3
@Raj Rj в ці дні я думаю, що це Redux
Олександр Т.

8
Redux сьогодні популярніший, його стиль походить від функціонального програмування. Якщо ви зі стилю OOP, Mobx ( mobxjs.github.io/mobx ) - це відмінна бібліотека управління державою, вона дозволяє зосередитись на написанні коду бізнесу та в кінцевому підсумку зменшує код котла
Nhan Tran

25

Ви можете перевірити архітектуру Flux . Я також рекомендую перевірити реалізацію React-Redux . Покладіть у свої дії дзвінки api. Це набагато чистіше, ніж все це складати в складі.

Дії - це на зразок допоміжних методів, які можна зателефонувати, щоб змінити стан програми або зробити дзвінки api.


Troper Дякую u. Тож чи варто зберігати дзвінки, пов'язані з API, в окремих файлах? І як я називаю їх у своєму "класі компонентів"? яку структуру папок слід дотримуватися? Яка найкраща практика? PS - я нова реагую, тому задаю основні питання.
Raj Rj

При відновленні впровадження до компонентів вводяться методи дій. Ці методи тепер стануть реквізитом до вашого компонента, який ви можете зателефонувати. Ви можете перевірити набір реагуючих-редукційних стартерів .
Jei Trooper

12

Використовуйте fetchметод всередині componentDidMountдля оновлення стану:

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

11

Ця дискусія тривала деякий час, і відповідь @Alexander T. дала хороший посібник, щоб слідкувати за новими, як на мене, React. І я поділюсь додатковими ноу-хау щодо виклику одного і того ж 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 в цілому: введіть тут опис зображення

Посилаючись на діаграму вище:

  • Розгортання API в componentDidMount()

    Власний сценарій для виклику API тут полягає в тому, що вміст (з відповіді API) цього компонента буде статичним, componentDidMount()запускається лише один раз, поки компонент монтується, навіть нові реквізити передаються з батьківського компонента або проводять дії re-rendering.
    Компонент перевіряє різницю, щоб повторно відобразити, але не перевстановити .
    Цитата від doc :

Якщо вам потрібно завантажити дані з віддаленої кінцевої точки, це хороше місце для екземпляру мережевого запиту.


  • Розгортання API в static getDerivedStateFromProps(nextProps, prevState)

Слід зауважити , що існує два види компонента поновлення , setState() в поточному компоненті б НЕ привести цей метод для запуску, але повторний рендеринг або нові підпори з батьківського компонента роблять. Ми могли дізнатися, що цей метод також спрацьовує під час монтажу.

Це правильне місце для розгортання API, якщо ми хочемо використовувати поточний компонент, як шаблон, а нові параметри для API - реквізити, що надходять від батьківського компонента .
Ми отримуємо іншу відповідь від API і повертаємо нову stateсюди, щоб змінити вміст цього компонента.

Наприклад: у
нас є випадаючий список для різних автомобілів у батьківському компоненті, цей компонент повинен відображати деталі вибраного.


  • Розгортання API в componentDidUpdate(prevProps, prevState)

static getDerivedStateFromProps()Цей метод відрізняється від кожного виводу, окрім початкового відображення. У нас може бути різниця в дзвінках і рендерингу API в одному компоненті.

Розширити попередній приклад:
Компонент для відображення деталей автомобіля може містити перелік серій цього автомобіля, якщо ми хочемо перевірити виробництво 2013 року, ми можемо натиснути або вибрати або ... пункт списку, щоб першим setState()відобразити це. поведінки (наприклад, виділення елемента списку) у цьому компоненті, а далі componentDidUpdate()ми надсилаємо наш запит із новими параметрами (стан). Отримавши відповідь, ми setState()знову надаємо різний зміст деталей автомобіля. Щоб наступне componentDidUpdate()не спричинило цикл нескінченності, нам потрібно порівняти стан, скориставшись prevStateна початку цього методу, щоб вирішити, чи надсилаємо API та надаємо новий вміст.

Цей метод справді можна використовувати так само, як static getDerivedStateFromProps()і для реквізиту, але потрібно впоратися зі змінами props, використовуючи prevProps. І нам потрібно співпрацювати, componentDidMount()щоб обробити початковий виклик API.

Цитата від doc :

... Це також гарне місце для здійснення мережевих запитів, якщо ви порівнюєте поточний реквізит з попередніми реквізитами ...


10

Я хотів би, щоб ви подивилися на файл redux http://redux.js.org/index.html

У них дуже чітко визначений спосіб обробки асинхронних дзвінків, тобто API-дзвінків, і замість того, щоб використовувати jQuery для викликів API, я хотів би порекомендувати використовувати файли для отримання або запити npm-пакетів, виборка в даний час підтримується сучасними браузерами, однак прошивка також доступна для сторона сервера.

Існує також ще один дивовижний суперагент пакету , який має багато варіантів під час запиту API та його дуже простий у використанні.


3

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


3

Ця частина документації React v16 дасть відповідь на ваше запитання, читайте про компонентDidMount ():

компонентDidMount ()

компонентDidMount () викликається відразу після встановлення компонента. Сюди повинна йти ініціалізація, яка вимагає вузлів DOM. Якщо вам потрібно завантажити дані з віддаленої кінцевої точки, це хороше місце для екземпляру мережевого запиту. Цей спосіб є хорошим місцем для налаштування будь-яких підписок. Якщо ви це зробите, не забудьте скасувати підписку в компонентWillUnmount ().

Як бачите, компонентDidMount вважається найкращим місцем і циклом для здійснення дзвінка api , а також доступу до вузла, означає, що до цього часу безпечно робити виклик, оновити представлення даних або все, що ви могли зробити, коли документ готовий, якщо ви використовуючи jQuery, він повинен якось нагадувати вам функцію document.ready (), де ви можете переконатися, що все готово для того, що ви хочете зробити у своєму коді ...


3

1) Ви можете використовувати API API F etch для отримання даних з Endd Points:

Приклад отримання всіх 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 ви можете вирізати середній крок передачі результатів 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 />}

2

Ви також можете отримувати дані за допомогою гачків у своїх функціональних компонентах

повний приклад з api call: https://codesandbox.io/s/jvvkoo8pq3

другий приклад: https://jsfiddle.net/bradcypert/jhrt40yv/6/

const Repos = ({user}) => {
  const [repos, setRepos] = React.useState([]);

  React.useEffect(() => {
    const fetchData = async () => {
        const response = await axios.get(`https://api.github.com/users/${user}/repos`);
        setRepos(response.data);
    }

    fetchData();
  }, []);

  return (
  <div>
    {repos.map(repo =>
      <div key={repo.id}>{repo.name}</div>
    )}
  </div>
  );
}

ReactDOM.render(<Repos user="bradcypert" />, document.querySelector("#app"))

1

Найкращим місцем і практикою для зовнішніх викликів API є метод React Lifecycle компонентDidMount () , де після виконання виклику API слід оновити локальний стан для запуску нового виклику методу render () , тоді зміни в оновленому локальному стані будуть буде застосовано до подання компонента.

Як інший варіант для початкового виклику зовнішнього джерела даних в React вказаний метод конструктора () класу. Конструктор - це перший метод, виконаний при ініціалізації екземпляра об'єктного компонента. Цей підхід ви можете бачити в прикладах документації для компонентів вищого порядку .

Метод компонентWillMount () та UNSAFE_componentWillMount () не слід використовувати для зовнішніх викликів API, оскільки вони призначені для застарілого використання. Тут ви можете побачити загальні причини, чому цей метод буде застарілим.

У будь-якому випадку ви ніколи не повинні використовувати метод render () або метод, безпосередньо викликаний від render (), як точку для зовнішнього виклику API. Якщо ви це зробите, ваша програма буде заблокована .


0

Чистим способом є здійснення асинхронного виклику API всередині компонентаDidMount за допомогою функції try / catch .

Коли ми зателефонували в API, ми отримаємо відповідь. Потім ми застосовуємо до нього метод JSON для перетворення відповіді в об’єкт JavaScript. Тоді ми беремо з цього об'єкта відповіді лише його дочірній об’єкт під назвою "результати" (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>
      )
}}

0

Було б чудово використовувати axios для запиту api, який підтримує скасування, перехоплювачі тощо. Поряд з axios, я використовую react-redux для управління станом та redux-saga / redux-thunk для побічних ефектів.


Хоча це невірно, оскільки використання axios і redux є дійсним способом отримання даних і управління станом, воно насправді не відповідає на питання, і це ближче до коментаря.
Еміль Бержерон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.