qual è il modo giusto per fare la chiamata API in reagire js?


137

Di recente mi sono trasferito da Angular a ReactJs. Sto usando jQuery per le chiamate API. Ho un'API che restituisce un elenco utenti casuale che deve essere stampato in un elenco.

Non sono sicuro di come scrivere le mie chiamate API. Qual è la migliore pratica per questo?

Ho provato quanto segue ma non ottengo alcun output. Sono aperto all'implementazione di librerie API alternative, se necessario.

Di seguito è il mio codice:

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
Dipendo dalla libreria di gestione dello stato che stai utilizzando. Se non si utilizza nessuno, è possibile spostare le chiamate API nel file separato e chiamare le funzioni API nella propria situazione nel componentDidMountcallback.
°

È possibile utilizzare al fetch()posto di jQuery se si utilizza jQuery solo per eseguire richieste Ajax.
Fred,

Perché usare Jquery? Jquery è un'enorme biblioteca ed è inutile
Robin,

Basta aggiungere qui che attualmente useEffectè probabilmente il posto giusto per fare chiamate API ora. Vedere btholt.github.io/complete-intro-to-react-v5/effects
SHW

Risposte:


98

In questo caso, è possibile effettuare una chiamata Ajax all'interno componentDidMounte quindi aggiornarestate

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
Ha funzionato, grazie .. Potresti suggerirmi "qual è la migliore biblioteca per una migliore gestione statale"
Raj Rj,

3
@Raj Rj in questi giorni penso che sia Redux
Alexander T.

8
Redux è più popolare in questi giorni, il suo stile deriva dalla programmazione funzionale. Se provieni dallo stile OOP, Mobx ( mobxjs.github.io/mobx ) è un'eccellente libreria di gestione dello stato, ti consente di concentrarti sulla scrittura del codice di bussiness e alla fine riduce il tuo codice di caldaia
Nhan Tran,

25

Potresti voler dare un'occhiata a Flux Architecture . Consiglio anche di dare un'occhiata all'implementazione di React-Redux . Metti le tue chiamate API nelle tue azioni. È molto più pulito del mettere tutto nel componente.

Le azioni sono una sorta di metodi di supporto che è possibile chiamare per modificare lo stato dell'applicazione o effettuare chiamate API.


Troper Grazie. Quindi, devo conservare le mie chiamate relative all'API in file separati? E come li chiamo nella mia "classe componente"? quale struttura di cartelle dovrei seguire? qual è la migliore pratica? PS: sono nuovo a reagire, quindi ponendo queste domande di base.
Raj Rj,

Nell'implementazione redux, i metodi di azione vengono iniettati nei componenti. Questi metodi diventeranno ora oggetti di scena per il tuo componente che puoi chiamare. Puoi dare un'occhiata al kit di reazione a redux-starter per la struttura.
Jei Trooper

12

Usa il fetchmetodo interno componentDidMountper aggiornare lo stato:

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

11

Questa discussione è stata per un po 'e la risposta di @Alexander T. ha fornito una buona guida da seguire per i più recenti di React come me. E condividerò alcune conoscenze aggiuntive su come chiamare la stessa API più volte per aggiornare il componente, penso che sia probabilmente un problema comune che i principianti potrebbero affrontare all'inizio.

componentWillReceiveProps(nextProps), dalla documentazione ufficiale :

Se è necessario aggiornare lo stato in risposta alle modifiche prop (ad esempio, per ripristinarlo), è possibile confrontare this.props e nextProps ed eseguire transizioni di stato utilizzando this.setState () in questo metodo.

Potremmo concludere che qui è il posto in cui gestiamo i puntelli dal componente padre, abbiamo chiamate API e stato di aggiornamento.

Basati sull'esempio di @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 (...)
  }
}

Aggiornare

componentWillReceiveProps() sarebbe deprecato.

Qui ci sono solo alcuni metodi (tutti in Doc ) nel ciclo di vita che penso siano collegati alla distribuzione dell'API in generale: inserisci qui la descrizione dell'immagine

Riferendosi al diagramma sopra:

  • Distribuire l'API in componentDidMount()

    Lo scenario corretto per far chiamare l'API qui è che il contenuto (dalla risposta dell'API) di questo componente sarà statico, sparerà componentDidMount()solo una volta mentre il componente sta montando, anche i nuovi oggetti di scena vengono passati dal componente padre o hanno azioni da condurre re-rendering.
    Il componente controlla la differenza per eseguire nuovamente il rendering ma non per il re-mount .
    Citazione dal documento :

Se è necessario caricare dati da un endpoint remoto, questo è un buon posto per creare un'istanza della richiesta di rete.


  • Distribuire l'API in static getDerivedStateFromProps(nextProps, prevState)

Dobbiamo notare che ci sono due tipi di aggiornamento dei componenti , setState() a componente corrente sarebbe non portare questo metodo per grilletto, ma ri-rendering o nuovi oggetti di scena di componente padre facciamo. Abbiamo scoperto che questo metodo si attiva anche durante il montaggio.

Questo è il posto giusto per distribuire l'API se vogliamo usare il componente corrente come un modello, ei nuovi parametri per l'API sono oggetti di scena provenienti dal componente padre .
Riceviamo una risposta diversa dall'API e ne restituiamo una nuova statequi per modificare il contenuto di questo componente.

Ad esempio:
abbiamo un elenco a discesa per diverse auto nel componente principale, questo componente deve mostrare i dettagli di quello selezionato.


  • Distribuire l'API in componentDidUpdate(prevProps, prevState)

Diversamente da static getDerivedStateFromProps(), questo metodo viene invocato immediatamente dopo ogni rendering tranne il rendering iniziale. Potremmo avere chiamate API e rendere la differenza in un componente.

Estendi l'esempio precedente:
il componente per mostrare i dettagli dell'auto potrebbe contenere un elenco di serie di questa auto, se vogliamo controllare quello di produzione 2013, possiamo fare clic o selezionare o ... l'elemento dell'elenco per portare un primo setState()a riflettere questo comportamento (come l'evidenziazione della voce di elenco) in questo componente e di seguito componentDidUpdate()inviamo la nostra richiesta con nuovi parametri (stato). Dopo aver ottenuto la risposta, siamo di setState()nuovo per il rendering dei diversi contenuti dei dettagli dell'auto. Per evitare che ciò componentDidUpdate()causi il ciclo infinito, è necessario confrontare lo stato utilizzando prevStateall'inizio di questo metodo per decidere se inviare l'API e rendere il nuovo contenuto.

Questo metodo potrebbe davvero essere utilizzato proprio come static getDerivedStateFromProps()con gli oggetti di scena, ma è necessario gestire i cambiamenti propsutilizzando prevProps. E dobbiamo collaborare con componentDidMount()per gestire la chiamata API iniziale.

Citazione dal documento :

... Questo è anche un buon posto per fare richieste di rete purché si confrontino gli oggetti di scena attuali con oggetti di scena precedenti ...


10

Vorrei che dai un'occhiata a redux http://redux.js.org/index.html

Hanno un modo ben definito di gestire le chiamate asincrone, ad esempio le chiamate API, e invece di utilizzare jQuery per le chiamate API, vorrei raccomandare l'uso di pacchetti di recupero o richiesta npm, il recupero è attualmente supportato dai browser moderni, ma è disponibile anche uno shim per lato server.

C'è anche un altro fantastico pacchetto superagente , che ha molte opzioni quando si effettua una richiesta API ed è molto facile da usare.


3

La funzione di rendering dovrebbe essere pura, significa che usa solo lo stato e gli oggetti di scena per il rendering, non provare mai a modificare lo stato nel rendering, questo di solito causa brutti bug e riduce significativamente le prestazioni. È inoltre utile separare il recupero dei dati e il rendering dei problemi nella tua app React. Ti consiglio di leggere questo articolo che spiega molto bene questa idea. https://medium.com/@learnreact/container-components-c0e67432e005#.sfydn87nm


3

Questa parte della documentazione di React v16 risponderà alla tua domanda, continua a leggere su componentDidMount ():

componentDidMount ()

componentDidMount () viene richiamato immediatamente dopo il montaggio di un componente. L'inizializzazione che richiede nodi DOM dovrebbe andare qui. Se è necessario caricare dati da un endpoint remoto, questo è un buon posto per creare un'istanza della richiesta di rete. Questo metodo è un buon posto per impostare qualsiasi abbonamento. Se lo fai, non dimenticare di annullare l'iscrizione in componentWillUnmount ().

Come vedi, componentDidMount è considerato il posto e il ciclo migliori per eseguire la chiamata API , anche accedere al nodo, significa che a questo punto è sicuro effettuare la chiamata, aggiornare la vista o qualunque cosa tu possa fare quando il documento è pronto, se lo sei usando jQuery, dovrebbe in qualche modo ricordarti la funzione document.ready (), dove puoi assicurarti che tutto sia pronto per qualsiasi cosa tu voglia fare nel tuo codice ...


3

1) È possibile utilizzare l' API F etch per recuperare i dati dai punti endd:

Esempio di recupero di tutto il Githubriposo per un utente

  /* 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) Altra alternativa è Axios

Utilizzando axios è possibile tagliare il passaggio intermedio del passaggio dei risultati della richiesta http al metodo .json (). Axios restituisce semplicemente l'oggetto dati che ti aspetteresti.

  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
            })
          );
}

Ora puoi scegliere di recuperare i dati utilizzando una di queste strategie in componentDidMount

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

  componentDidMount() {
    this.fetchData ();
  }

Nel frattempo puoi mostrare la barra di avanzamento durante il caricamento dei dati

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

2

È inoltre possibile recuperare i dati con hook nei componenti della funzione

esempio completo con chiamata api: https://codesandbox.io/s/jvvkoo8pq3

secondo esempio: 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

Come migliore posizione e pratica per le chiamate API esterne è il metodo React Lifecycle componentDidMount () , dove dopo l'esecuzione della chiamata API è necessario aggiornare lo stato locale per attivare la nuova chiamata del metodo render () , quindi le modifiche allo stato locale aggiornato essere applicato nella vista dei componenti.

Come altra opzione per la chiamata iniziale dell'origine dati esterna in React è indicato il metodo constructor () della classe. Il costruttore è il primo metodo eseguito all'inizializzazione dell'istanza dell'oggetto componente. È possibile visualizzare questo approccio negli esempi di documentazione per i componenti di ordine superiore .

Il metodo componentWillMount () e UNSAFE_componentWillMount () non devono essere utilizzati per le chiamate API esterne, poiché devono essere deprecati. Qui puoi vedere ragioni comuni, perché questo metodo sarà deprecato.

Comunque non devi mai usare il metodo render () o il metodo chiamato direttamente da render () come punto per una chiamata API esterna. In tal caso, l' applicazione verrà bloccata .


0

Un modo semplice è quello di effettuare una chiamata API asincrona all'interno di componentDidMount con la funzione try / catch .

Quando abbiamo chiamato un'API, riceviamo una risposta. Quindi applichiamo il metodo JSON su di esso, per convertire la risposta in un oggetto JavaScript. Quindi prendiamo da quell'oggetto di risposta solo il suo oggetto figlio chiamato "results" (data.results).

All'inizio abbiamo definito "userList" nello stato come un array vuoto. Non appena effettuiamo la chiamata API e riceviamo dati da tale API, assegniamo i "risultati" a userList usando il metodo setState .

All'interno della funzione di rendering diciamo che userList verrà dallo stato. Poiché la UserList è una matrice di oggetti che mappiamo attraverso di essa, per visualizzare un'immagine, un nome e un numero di telefono di ciascun "utente" dell'oggetto. Per recuperare queste informazioni utilizziamo la notazione a punti (ad es. User.phone).

NOTA : a seconda dell'API, la risposta potrebbe apparire diversa. Console.log l'intera "risposta" per vedere quali variabili sono necessarie, quindi assegnarle in 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

Sarebbe bello usare gli axios per la richiesta di api che supporta la cancellazione, gli intercettori ecc. Insieme agli axios, utilizzo il reagente-redux per la gestione dello stato e il redux-saga / redux-thunk per gli effetti collaterali.


Sebbene ciò non sia errato, poiché l'utilizzo di axios e redux è un modo valido per recuperare dati e gestire lo stato, in realtà non risponde alla domanda ed è più vicino a un commento.
Emile Bergeron,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.