¿Cuál es la forma correcta de hacer una llamada API en react js?

137

Recientemente me mudé de Angular a ReactJs. Estoy usando jQuery para llamadas API. Tengo una API que devuelve una lista de usuarios aleatorios que se imprimirá en una lista.

No estoy seguro de cómo escribir mis llamadas a la API. ¿Cuál es la mejor práctica para esto?

Intenté lo siguiente pero no obtengo ningún resultado. Estoy abierto a implementar bibliotecas API alternativas si es necesario.

Debajo está mi 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
fuente
2
Depende de qué biblioteca de administración de estado esté utilizando. Si no está utilizando ninguno, puede mover sus llamadas de API al archivo separado y llamar a las funciones de API en su situación en la componentDidMountdevolución de llamada.
1ven
Puede usar fetch()jQuery en lugar de jQuery si solo usa jQuery para hacer solicitudes de Ajax.
Fred
¿Por qué usar Jquery? Jquery es una gran biblioteca y es innecesaria
Robin
Simplemente agregue aquí que actualmente useEffectes probablemente el lugar para poner llamadas api ahora. Ver btholt.github.io/complete-intro-to-react-v5/effects
shw

Respuestas:

98

En este caso, puede hacer una llamada ajax dentro componentDidMounty luego actualizarstate

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.
fuente
2
Funcionó, gracias ... ¿Podría sugerirme "cuál es la mejor biblioteca para una mejor administración del estado"
Raj Rj
3
@Raj Rj en estos días creo que es Redux
Alexander T.
8
Redux es más popular en estos días, su estilo proviene de la programación funcional. Si viene del estilo OOP, Mobx ( mobxjs.github.io/mobx ) es una excelente biblioteca de administración de estado, le permite concentrarse en escribir código de negocios y reduce en última instancia su código repetitivo
Nhan Tran
25

Es posible que desee consultar la arquitectura de flujo . También recomiendo revisar la implementación de React-Redux . Pon tus llamadas de API en tus acciones. Es mucho más limpio que ponerlo todo en el componente.

Las acciones son una especie de métodos auxiliares a los que puede llamar para cambiar el estado de su aplicación o hacer llamadas API.

Jei Trooper
fuente
Troper Gracias. Entonces, ¿debo mantener mis llamadas relacionadas con la API en archivos separados? ¿Y cómo los llamo en mi "clase de componentes"? ¿Qué estructura de carpetas debo seguir? ¿Cuál es la mejor práctica? PD: Soy nuevo en reaccionar, así que hago estas preguntas básicas.
Raj Rj
En la implementación redux, los métodos de acción se inyectan a los componentes. Estos métodos ahora se convertirán en accesorios para su componente al que puede llamar. Puede consultar react-redux-starter-kit para la estructura.
Jei Trooper
12

Use el fetchmétodo interno componentDidMountpara actualizar el estado:

componentDidMount(){
  fetch('https://randomuser.me/api/')
      .then(({ results }) => this.setState({ person: results }));
}
amor por la codificación
fuente
11

Esta discusión ha sido durante un tiempo y la respuesta de @Alexander T. proporcionó una buena guía a seguir para los nuevos de React como yo. Y voy a compartir algunos conocimientos adicionales sobre cómo llamar a la misma API varias veces para actualizar el componente, creo que probablemente sea un problema común que los novatos pueden enfrentar al principio.

componentWillReceiveProps(nextProps), de la documentación oficial :

Si necesita actualizar el estado en respuesta a los cambios de prop (por ejemplo, para restablecerlo), puede comparar this.props y nextProps y realizar transiciones de estado usando this.setState () en este método.

Podríamos concluir que aquí es donde manejamos los accesorios del componente principal, tenemos llamadas de API y actualizamos el estado.

Base en el ejemplo 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 (...)
  }
}

Actualizar

componentWillReceiveProps() Sería obsoleto.

Aquí hay solo algunos métodos (todos en Doc ) en el ciclo de vida que creo que estarían relacionados con la implementación de API en general: ingrese la descripción de la imagen aquí

Al referirse al diagrama anterior:

  • Implementar API en componentDidMount()

    El escenario adecuado para tener una llamada a la API aquí es que el contenido (de la respuesta de la API) de este componente será estático, componentDidMount()solo se disparará una vez mientras el componente se está montando, incluso se pasan nuevos accesorios del componente principal o tienen acciones para liderar re-rendering.
    El componente verifica la diferencia para volver a renderizar pero no para volver a montar .
    Cita del doc :

Si necesita cargar datos desde un punto final remoto, este es un buen lugar para instanciar la solicitud de red.


  • Implementar API en static getDerivedStateFromProps(nextProps, prevState)

Debemos notar que hay dos tipos de actualización de componentes , setState() en la componente de corriente que no conduzcan a este método gatillo, pero re-representación o nuevos apoyos de componente de los padres hacemos. Podríamos descubrir que este método también se activa durante el montaje.

Este es un lugar adecuado para implementar API si queremos usar el componente actual como una plantilla, y los nuevos parámetros para API son accesorios que provienen del componente principal .
Recibimos una respuesta diferente de API y devolvemos una nueva stateaquí para cambiar el contenido de este componente.

Por ejemplo:
tenemos una lista desplegable para diferentes automóviles en el componente principal, este componente debe mostrar los detalles del seleccionado.


  • Implementar API en componentDidUpdate(prevProps, prevState)

A diferencia de static getDerivedStateFromProps(), este método se invoca inmediatamente después de cada representación, excepto la representación inicial. Podríamos tener llamadas de API y representar la diferencia en un componente.

Extienda el ejemplo anterior:
el componente para mostrar los detalles del automóvil puede contener una lista de series de este automóvil, si queremos verificar el de producción de 2013, podemos hacer clic o seleccionar o ... el elemento de la lista para liderar un primero setState()para reflejar esto comportamiento (como resaltar el elemento de la lista) en este componente y, a continuación componentDidUpdate(), enviamos nuestra solicitud con nuevos parámetros (estado). Después de obtener la respuesta, setState()nuevamente para mostrar el contenido diferente de los detalles del automóvil. Para evitar que lo siguiente componentDidUpdate()provoque el bucle infinito, necesitamos comparar el estado utilizando prevStateal principio de este método para decidir si enviamos la API y representamos el nuevo contenido.

Este método realmente podría utilizarse al igual que static getDerivedStateFromProps()con los accesorios, pero necesita manejar los cambios propsmediante la utilización prevProps. Y tenemos que cooperar componentDidMount()para manejar la llamada API inicial.

Cita del doc :

... Este también es un buen lugar para hacer solicitudes de red siempre que compare los accesorios actuales con los accesorios anteriores ...

Carr
fuente
10

Me gustaría que eche un vistazo a redux http://redux.js.org/index.html

Tienen una forma muy bien definida de manejar llamadas asíncronas, es decir, llamadas API, y en lugar de usar jQuery para llamadas API, me gustaría recomendar el uso de fetch o solicitar paquetes npm, fetch es compatible actualmente con los navegadores modernos, pero también hay un shim disponible para lado del servidor.

También existe otro paquete sobresaliente increíble , que tiene muchas opciones al hacer una solicitud de API y es muy fácil de usar.

Devarsh Shah
fuente
3

La función de renderizado debe ser pura, significa que solo usa estado y accesorios para renderizar, nunca intente modificar el estado en render, esto generalmente causa errores feos y disminuye significativamente el rendimiento. También es un buen punto si separa la búsqueda de datos y las preocupaciones de procesamiento en su aplicación React. Le recomiendo que lea este artículo que explica muy bien esta idea. https://medium.com/@learnreact/container-components-c0e67432e005#.sfydn87nm

Nhan Tran
fuente
3

Esta parte de la documentación de React v16 responderá a su pregunta, siga leyendo sobre componentDidMount ():

componentDidMount ()

componentDidMount () se invoca inmediatamente después de montar un componente. La inicialización que requiere nodos DOM debería ir aquí. Si necesita cargar datos desde un punto final remoto, este es un buen lugar para instanciar la solicitud de red. Este método es un buen lugar para configurar cualquier suscripción. Si hace eso, no olvide darse de baja en componentWillUnmount ().

Como puede ver, componentDidMount se considera el mejor lugar y ciclo para hacer la llamada API , también acceder al nodo, lo que significa que en este momento es seguro hacer la llamada, actualizar la vista o lo que sea que pueda hacer cuando el documento esté listo, si está usando jQuery, debería recordarle de alguna manera la función document.ready (), donde puede asegurarse de que todo esté listo para lo que quiera hacer en su código ...

Alireza
fuente
3

1) Puede usar F etch API para obtener datos de Endd Points:

Ejemplo obteniendo todo el Githubreposo para un usuario

  /* 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) Otra alternativa es Axios

Con axios puede cortar el paso intermedio de pasar los resultados de la solicitud http al método .json (). Axios simplemente devuelve el objeto de datos que esperaría.

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

Ahora puede elegir obtener datos utilizando cualquiera de estas estrategias en componentDidMount

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

  componentDidMount() {
    this.fetchData ();
  }

Mientras tanto, puede mostrar la barra de progreso mientras se cargan los datos

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

También puede buscar datos con ganchos en los componentes de su función

ejemplo completo con llamada api: https://codesandbox.io/s/jvvkoo8pq3

segundo ejemplo: 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
fuente
1

Como el mejor lugar y práctica para las llamadas API externas es el método React Lifecycle componentDidMount () , donde después de la ejecución de la llamada API debe actualizar el estado local para que se active la nueva llamada al método render () , luego los cambios en el estado local actualizado se aplicará en la vista de componentes.

Como otra opción para la llamada de fuente de datos externa inicial en React se señala el método constructor () de la clase El constructor es el primer método ejecutado en la inicialización de la instancia del objeto componente. Puede ver este enfoque en los ejemplos de documentación para Componentes de orden superior .

El método componentWillMount () y UNSAFE_componentWillMount () no debe usarse para llamadas a API externas, porque están destinadas a ser obsoletas. Aquí puede ver razones comunes por las que este método quedará en desuso.

De todos modos, nunca debe usar el método render () o el método directamente llamado desde render () como un punto para una llamada API externa. Si haces esto, tu aplicación será bloqueada .

zdrsoft
fuente
0

Una forma limpia es hacer una llamada API asíncrona dentro de componentDidMount con la función try / catch .

Cuando llamamos a una API, recibimos una respuesta. Luego aplicamos el método JSON para convertir la respuesta en un objeto JavaScript. Luego tomamos de ese objeto de respuesta solo su objeto hijo llamado "resultados" (data.results).

Al principio definimos "userList" en estado como una matriz vacía. Tan pronto como hacemos la llamada a la API y recibimos datos de esa API, asignamos los "resultados" a userList usando el método setState .

Dentro de la función de procesamiento, decimos que userList vendrá del estado. Dado que userList es una matriz de objetos que mapeamos a través de ella, para mostrar una imagen, un nombre y un número de teléfono de cada objeto "usuario". Para recuperar esta información, usamos la notación de puntos (por ejemplo, user.phone).

NOTA : dependiendo de su API, su respuesta puede verse diferente. Console.log toda la "respuesta" para ver qué variables necesita de ella y luego asignarlas en 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
fuente
0

Sería genial usar axios para la solicitud de API que admite cancelaciones, interceptores, etc. Junto con axios, uso react-redux para la gestión del estado y redux-saga / redux-thunk para los efectos secundarios.

Shivang Gupta
fuente
Si bien esto no es incorrecto, ya que usar axios y redux es una forma válida de obtener datos y administrar el estado, en realidad no responde la pregunta y está más cerca de un comentario.
Emile Bergeron