React. How to show data loading message on API call

Viewed 48

Trying to render an API call which returns an array of products.

How to show loading message on products render. (Currently the "loading" message is not being displayed)

useGetProducts.js

import { useEffect, useState } from "react";
import axios from "axios";

const useGetProducts = (API) => {
  const [products, setProducts] = useState(null);
  const [error, setError] = useState("");
  const [loaded, setLoaded] = useState(false);
  useEffect(() => {
    (async () => {
      try {
        async function fetchData() {
          const response = await axios(API);
          setProducts(response.data)
        }
        fetchData();
        
      } catch (error) {
        setError(error.message);
      } finally {
        setLoaded(true);
      }
    })();
  }, []);

  return { products, error, loaded };
};

export default useGetProducts

ProductList.js

import React from "react";
import ProductItem from "./ProductItem";
import useGetProducts from "../hooks/useGetProducts";
import { Link } from "react-router-dom";
import { API } from '../constants/constants';

const ProductList = () => {
  const data = useGetProducts(`${API}?limit=9&offset=0`);

  return (
    <section className="theme-section">
      {data.loaded ? 
        <>
        {data.products && data.products.map((product) => (
          <div key={product.id}>            
            <ProductItem product={product} />
            <Link to={`/product/${product.id}`}>ver detalle</Link>
            <br /><br />
            <hr />
          </div>
        ))}
        </>
        : "loading"
      }
      
    </section>
  )
}

export default ProductList;

Currently the message is not being displayed

2 Answers

What is happening here is that you're calling fetchData without waiting for it, which is immediately setting loaded to true.

I don't think there is a need for the fetchData function here, so either remove it or await it:

const [products, setProducts] = useState(null);
const [error, setError] = useState("");
const [loaded, setLoaded] = useState(false);
useEffect(() => {
  (async () => {
      const response = await axios(API);
      setProducts(response.data)
    } catch (error) {
      setError(error.message);
    } finally {
      setLoaded(true);
    }
  })();
}, []);

set your loaded state to false when you enter in fetchData function and in finally method, update loaded state to true.

useEffect(() => {
    (async () => {
      try {
        async function fetchData() {
          setLoaded(false);
          const response = await axios(API);
          setProducts(response.data);
        }
        fetchData();
        
      } catch (error) {
        setError(error.message);
      } finally {
        setLoaded(true);
      }
    })();
  }, []);
Related