Home > Software design >  React: Why on .map an array doesn't show list of items?
React: Why on .map an array doesn't show list of items?

Time:11-19

I'm trying to show list of items that i get from an API in the backend. However, when I try to map the array, then it doesn't show any item. What am I doing wrong? Anyone could help please?

I tried to console log and I can see list of items being fetched correctly. The h2 tag also displays. but not the .map results.

This is the code:

interface Props {
  products: Product[] | [];
}

const ProductsList = ({ products }: Props) => {
  useEffect(() => {
    getProducts();
    console.log('fetched data', getProducts());
  }, []);

  return (
    <RootContainer>
      <h2>test</h2>
      {products &&
        products.map((product) => {
          return <ProductItem key={product.id} product={product} />;
        })}
    </RootContainer>
  );
};

export default ProductsList;

This is the getProducts() function that fetch data from another port.

const getProducts = async () => {
  let API_URL = 'http://localhost:5000/api/Products';

  const response: any = await fetch(API_URL);
  const data = await response.json();

  return data;
};
export default getProducts;

CodePudding user response:

I think the issue may be that you are retrieving the products but not actually doing anything with them - therefore the "products" check you perform before iterating will return false.

Try using a state variable:

const ProductsList = () => {

  const [products, setProducts] = useState<product[]>();

  useEffect(() => {
    getProducts().then((result) => setProducts(result);
  }, []);

  return (
    <RootContainer>
      <h2>test</h2>
      {products &&
        products.map((product) => {
          return <ProductItem key={product.id} product={product} />;
        })}
    </RootContainer>
  );
};
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

The principal here is that when the getProducts() method returns it will update the state variable with a list of products. This change in state will cause the component to refresh and the products.map will be reached.

CodePudding user response:

You are fetching the products on the useEffect hook but are not storing them as a state value. Try using useState to achieve that, and try tweaking your rendering logic.


import {useState, useEffect} from 'react';
//...

interface Props {
  products: Product[] | [];
}

const ProductsList = (props: Props) => {

  const [products, setProducts] = useState<Product[]>([]);

  useEffect(() => {
    const _products = getProducts();
    console.log('fetched data',_products);
    setProducts(_products);
  }, []);

  return (
    <RootContainer>
      <h2>test</h2>
      {products &&
        products.map((product) => {
          return <ProductItem key={product.id} product={product} />;
        })}
    </RootContainer>
  );
};

export default ProductsList;

If you still don't see anything, try modifying your rendering logic like so:


<RootContainer>
    <h2>test</h2>
    {products && products.map((product) => 
        (<ProductItem key={product.id} product={product} />)
    )}
</RootContainer>

Since you are using TypeScript, conditional rendering needs to be handled a bit differently than from JS. So in your check for products && try this:

<RootContainer>
    <h2>test</h2>
    {products ? products.map((product) => (
        <ProductItem key={product.id} product={product} />)
        : null
     )}
</RootContainer>

Now, depending on the props you've defined for the RootContainer component, passing a null as a child might not be allowed. If that's the case, try changing the null to <></> to pass a React Fragment instead

  • Related