10 - Peticiones con la API fetch en React

Cuando necesitamos hacer peticiones a un servidor web podemos utilizar el API fetch de Javascript. Nos permite obtener en forma asíncrona recursos de un servidor web.

Problema

Confeccionar una aplicación que recupere una respuesta en JSON de la dirección:

https://scratchya.com.ar/react/datos.php

La estructura del archivo JSON es:

[
  {
    "codigo": 1,
    "descripcion": "papas",
    "precio": 12.33
  },
  {
    "codigo": 2,
    "descripcion": "manzanas",
    "precio": 54
  }
]

Luego de recuperar los datos mostrarlos en una tabla HTML

El primer paso será crear el proyecto010 desde la línea de comandos de Node.js mediante la aplicación create-react-app

App.js

import { useState, useEffect } from 'react';

function App() {

  const [articulos, setArticulos] = useState([])

  useEffect(() => {
    fetch('https://scratchya.com.ar/react/datos.php')
      .then((response) => {
        return response.json()
      })
      .then((articulos) => {
        setArticulos(articulos)
      })
  }, [])

  return (
    <div>
      <table border="1">
        <thead>
          <tr>
            <th>Código</th>
            <th>Descripción</th>
            <th>Precio</th>
          </tr>
        </thead>
        <tbody>
          {articulos.map(art => {
            return (
              <tr key={art.codigo}>
                <td>{art.codigo}</td>
                <td>{art.descripcion}</td>
                <td>{art.precio}</td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}

export default App

Recordemos que uno de los objetivos de los Hook de efectos son las peticiones de datos a un servidor:

  useEffect(() => {
    fetch('https://scratchya.com.ar/react/datos.php')
      .then((response) => {
        return response.json()
      })
      .then((articulos) => {
        setArticulos(articulos)
      })
  }, [])

Definimos una variable de estado para almacenar un arreglo con todos los productos recuperados del servidor:

  const [articulos, setArticulos] = useState([])

El el bloque JSX se muestra la cabecera de la tabla HTML y mediante el recorrido de la variable de estado se muestran los artículos recuperados del servidor:

  return (
    <div>
      <table border="1">
        <thead>
          <tr>
            <th>Código</th>
            <th>Descripción</th>
            <th>Precio</th>
          </tr>
        </thead>
        <tbody>
          {articulos.map(art => {
            return (
              <tr key={art.codigo}>
                <td>{art.codigo}</td>
                <td>{art.descripcion}</td>
                <td>{art.precio}</td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );

Cuando ejecutamos la aplicación tenemos como resultado:

peticiones fetch react

Cuando hay peticiones a un servidor puede haber un tiempo de espera hasta que se recuperan los datos. Vamos a modificar el ejercicio anterior para que se muestre un mensaje hasta que lleguen los datos del servidor:

import { useState, useEffect } from 'react';

function App() {

  const [articulos, setArticulos] = useState([])
  const [recuperado, setRecuperado] = useState(false)


  function mostrarTabla() {
    return (
      <div>
        <table border="1">
          <thead>
            <tr>
              <th>Código</th>
              <th>Descripción</th>
              <th>Precio</th>
            </tr>
          </thead>
          <tbody>
            {articulos.map(art => {
              return (
                <tr key={art.codigo}>
                  <td>{art.codigo}</td>
                  <td>{art.descripcion}</td>
                  <td>{art.precio}</td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
    );
  }

  useEffect(() => {
    fetch('https://scratchya.com.ar/react/datos.php')
      .then((response) => {
        return response.json()
      })
      .then((articulos) => {
        setArticulos(articulos)
        setRecuperado(true)
      })
  }, [])

  if (recuperado)
    return mostrarTabla()
  else
    return (<div>recuperando datos...</div>)
}

export default App

Hemos guardado dos variables de estado, el vector con los datos a imprimir y una bandera que indica si los datos fueron recuperados del servidor:

  const [articulos, setArticulos] = useState([])
  const [recuperado, setRecuperado] = useState(false)

Cuando realmente tenemos todos los datos recuperados procedemos a modificar las dos variables de estado:

  useEffect(() => {
    fetch('https://scratchya.com.ar/react/datos.php')
      .then((response) => {
        return response.json()
      })
      .then((articulos) => {
        setArticulos(articulos)
        setRecuperado(true)
      })
  }, [])

Donde generamos el bloque JSX, según la variable de estado 'recuperado' procedemos a mostrar la tabla HTML o un div con un mensaje de información:

  if (recuperado)
    return mostrarTabla()
  else
    return (<div>recuperando datos...</div>)

Posiblemente el tiempo de respuesta en este problema es muy pequeño y no alcancemos a ver el mensaje por pantalla, podemos modificar temporalmente el programa y hacer que espere 2 segundos antes de recuperar los datos (esto es solo a modo de prueba y no tiene sentido en este problema esperar):

  useEffect(() => {
    fetch('https://scratchya.com.ar/react/datos.php')
      .then((response) => {
        return response.json()
      })
      .then((articulos) => {
        setTimeout(() => {
          setArticulos(articulos)
          setRecuperado(true)
        }, 2000);
      })
  }, [])

Con esto tenemos la oportunidad de ver el mensaje:

fetch react