qual é a maneira correta de fazer a chamada da API no react js?

137

Recentemente, mudei de Angular para ReactJs. Estou usando o jQuery para chamadas de API. Eu tenho uma API que retorna uma lista aleatória de usuários que deve ser impressa em uma lista.

Não sei como escrever minhas chamadas de API. Qual é a melhor prática para isso?

Eu tentei o seguinte, mas não estou obtendo nenhuma saída. Estou aberto a implementar bibliotecas de API alternativas, se necessário.

Abaixo está o meu código:

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>
    )
  }
}
Raj Rj
fonte
2
Depende de qual biblioteca de gerenciamento de estado você está usando. Se você não estiver usando nenhum, poderá mover as chamadas da API para o arquivo separado e chamar as funções da API na sua situação no componentDidMountretorno de chamada.
1ven
Você pode usar em fetch()vez do jQuery se usar apenas o jQuery para fazer solicitações do Ajax.
Fred
Por que usar o Jquery? JQuery é uma biblioteca enorme e é desnecessário
Robin
Basta adicionar aqui que atualmente useEffecté provavelmente o lugar para fazer chamadas de API agora. Veja btholt.github.io/complete-intro-to-react-v5/effects
shw

Respostas:

98

Nesse caso, você pode fazer uma chamada ajax dentro componentDidMounte atualizarstate

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>
    );
  }
}
Alexander T.
fonte
2
Funcionou, graças .. Você poderia por favor me sugerir "qual é a melhor biblioteca para uma melhor gestão do Estado"
Raj Rj
3
@Raj Rj nestes dias eu acho que é Redux
Alexander T.
8
Redux é mais popular atualmente, seu estilo vem da programação funcional. Se você vem de estilo OOP, Mobx ( mobxjs.github.io/mobx ) é uma excelente biblioteca de gerenciamento de estado, ele permite que você se concentrar em escrever código bussiness e reduz em última análise, o seu código clichê
Nhan Tran
25

Você pode querer verificar a arquitetura Flux . Também recomendo verificar a Implementação do React-Redux . Coloque suas chamadas de API em suas ações. É muito mais limpo do que colocar tudo no componente.

Ações são tipos de métodos auxiliares que você pode chamar para alterar o estado do aplicativo ou fazer chamadas de API.

Jei Trooper
fonte
Troper Obrigado. Então, devo manter minhas chamadas relacionadas à API em arquivos separados? E como eu os chamo na minha "classe componente"? Que estrutura de pastas devo seguir? Qual é a melhor prática? PS: Eu sou novo em reagir, fazendo as perguntas básicas.
Raj Rj
Na implementação do redux, os métodos de ação são injetados nos componentes. Esses métodos agora se tornarão acessórios para o seu componente, que você pode chamar. Você pode conferir o kit react-redux-starter-kit para a estrutura.
amigos estão dizendo sobre jei trooper
12

Use o fetchmétodo inside componentDidMountpara atualizar o estado:

componentDidMount(){
  fetch('https://randomuser.me/api/')
      .then(({ results }) => this.setState({ person: results }));
}
amor pela codificação
fonte
11

Essa discussão já dura um tempo e a resposta de @Alexander T. forneceu um bom guia a seguir para os mais novos do React como eu. E vou compartilhar alguns conhecimentos adicionais sobre como chamar a mesma API várias vezes para atualizar o componente. Acho que provavelmente é um problema comum que o novato pode enfrentar no início.

componentWillReceiveProps(nextProps), da documentação oficial :

Se você precisar atualizar o estado em resposta a alterações de prop (por exemplo, para redefini-lo), poderá comparar this.props e nextProps e executar transições de estado usando this.setState () neste método.

Podemos concluir que aqui é o local em que manipulamos objetos do componente pai, temos chamadas de API e atualizamos o estado.

Com base no exemplo de @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 (...)
  }
}

Atualizar

componentWillReceiveProps() seria preterido.

Aqui estão apenas alguns métodos (todos eles no Doc ) no ciclo de vida que eu acho que estariam relacionados à implantação da API no caso geral: insira a descrição da imagem aqui

Ao referir o diagrama acima:

  • Implantar API no componentDidMount()

    O cenário adequado para a chamada da API aqui é que o conteúdo (da resposta da API) desse componente será estático, seja acionado componentDidMount()apenas uma vez enquanto o componente estiver montando, até mesmo novos adereços serão transmitidos do componente pai ou terão ações para liderar re-rendering.
    O componente verifica a diferença para renderizar novamente, mas não para montar novamente .
    Citação de doc :

Se você precisar carregar dados de um terminal remoto, este é um bom lugar para instanciar a solicitação de rede.


  • Implantar API no static getDerivedStateFromProps(nextProps, prevState)

Devemos notar que existem dois tipos de atualização componente , setState() em componente atual que não levam esse método para gatilho, mas re-renderização ou novos adereços de componente pai fazer. Poderíamos descobrir que esse método também é acionado durante a montagem.

Este é um local adequado para implementar a API, se quisermos usar o componente atual como um modelo, e os novos parâmetros para a API são adereços provenientes do componente pai .
Recebemos uma resposta diferente da API e retornamos um novo stateaqui para alterar o conteúdo deste componente.

Por exemplo:
Temos uma lista suspensa para carros diferentes no componente pai, esse componente precisa mostrar os detalhes do carro selecionado.


  • Implantar API no componentDidUpdate(prevProps, prevState)

Difere da static getDerivedStateFromProps() , esse método é chamado imediatamente após cada renderização, exceto a renderização inicial. Poderíamos ter chamadas de API e renderizar diferença em um componente.

Estenda o exemplo anterior:
O componente para mostrar os detalhes do carro pode conter uma lista de séries deste carro; se quisermos verificar a produção de 2013, podemos clicar ou selecionar ou ... o item da lista para liderar primeiro setState()a refletir isso comportamento (como destacar o item da lista) nesse componente e, a seguir componentDidUpdate(), enviamos nossa solicitação com novos parâmetros (estado). Depois de obter a resposta, setState()novamente por renderizar o conteúdo diferente dos detalhes do carro. Para impedir que o seguinte componentDidUpdate()cause o loop infinito, precisamos comparar o estado utilizando prevStateno início deste método para decidir se enviaremos a API e renderizaremos o novo conteúdo.

Esse método realmente pode ser utilizado da mesma maneira que static getDerivedStateFromProps()com adereços, mas é necessário lidar com as alterações propsutilizando prevProps. E precisamos cooperar componentDidMount()para lidar com a chamada inicial da API.

Citação de doc :

... Esse também é um bom lugar para fazer solicitações de rede, desde que você compare os adereços atuais aos adereços anteriores ...

Carr
fonte
10

Gostaria que você desse uma olhada no redux http://redux.js.org/index.html

Eles têm uma maneira muito bem definida de lidar com chamadas assíncronas, ou seja, chamadas de API e, em vez de usar o jQuery para chamadas de API, eu gostaria de recomendar o uso de buscar ou solicitar pacotes npm, atualmente a busca é suportada por navegadores modernos, mas um shim também está disponível para lado do servidor.

Há também esse outro superagente de pacote incrível , que tem muitas opções ao fazer uma solicitação de API e é muito fácil de usar.

Devarsh Shah
fonte
3

A função Render deve ser pura, significa que ele usa apenas state e props para renderizar, nunca tente modificar o estado na renderização, isso geralmente causa erros feios e diminui significativamente o desempenho. Também é um bom ponto se você separar a busca de dados e apresentar preocupações no seu React App. Eu recomendo que você leia este artigo, que explica muito bem essa ideia. https://medium.com/@learnreact/container-components-c0e67432e005#.sfydn87nm

Nhan Tran
fonte
3

Esta parte da documentação do React v16 responderá à sua pergunta, leia sobre componentDidMount ():

componentDidMount ()

componentDidMount () é chamado imediatamente após a montagem de um componente. A inicialização que requer nós DOM deve ir aqui. Se você precisar carregar dados de um terminal remoto, este é um bom lugar para instanciar a solicitação de rede. Este método é um bom lugar para configurar quaisquer assinaturas. Se você fizer isso, não se esqueça de cancelar a inscrição em componentWillUnmount ().

Como você vê, componentDidMount é considerado o melhor local e ciclo para fazer a chamada da API , também acessa o nó, significa que agora é seguro fazer a chamada, atualizar a visualização ou o que você poderia fazer quando o documento estiver pronto, se você estiver usando o jQuery, ele deve lembrá-lo de alguma maneira a função document.ready (), onde você pode garantir que tudo esteja pronto para o que você deseja fazer no seu código ...

Alireza
fonte
3

1) Você pode usar a API F etch para buscar dados dos Endd Points:

Exemplo de busca de todos os Githubrepouso para um usuário

  /* 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) Outra alternativa é Axios

Usando axios, você pode cortar a etapa intermediária de passar os resultados da solicitação http para o método .json (). Axios apenas retorna o objeto de dados que você esperaria.

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

Agora você pode optar por buscar dados usando qualquer uma dessas estratégias em componentDidMount

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

  componentDidMount() {
    this.fetchData ();
  }

Enquanto isso, você pode mostrar a barra de progresso enquanto os dados estão sendo carregados

   {this.state.isLoading && <LinearProgress />}
Hitesh Sahu
fonte
2

Você também pode buscar dados com ganchos nos componentes de função

exemplo completo com chamada da API: https://codesandbox.io/s/jvvkoo8pq3

segundo exemplo: 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"))
iamnotsam
fonte
1

Como o melhor local e prática para chamadas externas à API é o método React Lifecycle method componentDidMount () , onde após a execução da chamada da API você deve atualizar o estado local para acionar a nova chamada do método render () , as alterações no estado local atualizado serão ser aplicado na visualização do componente.

Como outra opção para a chamada de fonte de dados externa inicial no React, é apontado o método constructor () da classe. O construtor é o primeiro método executado na inicialização da instância do objeto componente. Você pode ver essa abordagem nos exemplos de documentação para componentes de ordem superior .

O método componentWillMount () e UNSAFE_componentWillMount () não devem ser usados ​​para chamadas de API externas, porque elas devem ser descontinuadas. Aqui você pode ver os motivos mais comuns pelos quais esse método será descontinuado.

De qualquer forma, você nunca deve usar o método render () ou o método chamado diretamente de render () como um ponto para chamada de API externa. Se você fizer isso, seu aplicativo será bloqueado .

zdrsoft
fonte
0

Uma maneira limpa é fazer uma chamada de API assíncrona dentro do componentDidMount com a função try / catch .

Quando chamamos uma API, recebemos uma resposta. Em seguida, aplicamos o método JSON nele, para converter a resposta em um objeto JavaScript. Em seguida, extraímos desse objeto de resposta apenas o objeto filho chamado "results" (data.results).

No começo, definimos "userList" no estado como uma matriz vazia. Assim que fazemos a chamada da API e recebemos dados dessa API, atribuímos os "resultados" a userList usando o método setState .

Dentro da função render, dizemos que userList será proveniente do estado. Como o userList é um conjunto de objetos, mapeamos através dele, para exibir uma imagem, um nome e um número de telefone de cada objeto "usuário". Para recuperar essas informações, usamos notação de ponto (por exemplo, user.phone).

NOTA : dependendo da sua API, sua resposta pode parecer diferente. Console.log toda a "resposta" para ver de quais variáveis ​​você precisa e depois atribuí-las em 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>
      )
}}
Tania Shulga
fonte
0

Seria ótimo usar axios para a solicitação da API, que suporta cancelamentos, interceptores etc. Junto com os axios, eu uso o react-redux para gerenciamento de estado e o redux-saga / redux-thunk para os efeitos colaterais.

Shivang Gupta
fonte
Embora isso não esteja incorreto, como o uso de axios e redux é uma maneira válida de buscar dados e gerenciar estado, na verdade, ele não responde à pergunta e está mais próximo de um comentário.
Emile Bergeron