Home > OS >  Get data from API by map function
Get data from API by map function

Time:05-04

I'm running into a problem that I've been working on for days and unfortunately I can't figure it out by myself. I'm trying to create a View which shows some information from an API. But every time I map this item, I want to do another API call which checks the live price of that product.

So I have for example some JSON data what I get from an API.

{
    "id": 1,
    "name": "test product",
    "productid": "73827duf"    
},
{
    "id": 2,
    "name": "test product2",
    "productid": "734437dde"    
}

So I show this data with the following code inside my application:

{item.products.map((products) => {
     return (
        <View
           key={products.id}
        >
             <Text
                 style={{
                    fontSize: FONTS.body3,
                    paddingLeft: 10,
                 }}
             >
                   {products.name}
                   {getProductPriceJumbo(
                       products.productid
                   )}
             </Text>
       </View>
     );
})}

So I want to run every time a function which fetches data from another API. I'm sending the productID because that's the only information I need to call this API. You can see this function down below:

function getProductPriceJumbo(id) {
   fetch("https://---/test.php?id="   id   "/", {
      method: "GET",
   })
      .then((response) => response.json())
      .then((data) => {
          return data[0].price;
      });
    }

So this fetch returns a big list with information about the product from a third party API. I only want to return the price, that's the reason why I only return the price value and I want to print this out on the view above. I can't really figure out how to do this. I get undefined from the function every time I run it. Hope someone can help me with this.

CodePudding user response:

Create a new Price Component to display the price

function Price({ id }) {
  const [price, setPrice] = useState(0);

  useEffect(() => {
    function getProductPriceJumbo(id) {
      fetch("https://---/test.php?id="   id   "/", {
        method: "GET"
      })
        .then((response) => response.json())
        .then((data) => {
          setPrice(data[0].price);
        });
    }

    getProductPriceJumbo(id);
  },[]);

  return <Text>{price}</Text>;
}

And your .map will become

{
  item.products.map((products) => {
    return (
      <View key={products.id}>
        <Text
          style={{
            fontSize: FONTS.body3,
            paddingLeft: 10
          }}
        >
          {products.name}
          <Price id={products.productid} />
        </Text>
      </View>
    );
  });
}

CodePudding user response:

The reason you are getting undefined is because the window is rendering before the function finishes running. You will have define an asynchronous function before you return your view.

const [data, setData] = useState([])
const [loading, setLoading] = useState(true);

useEffect(() => {
   const fetchData = async () =>{
   setLoading(true);
   try {
          const {data: response} = await axios.get('API URL');
          setData(response);
   } catch (error) {
       console.error(error.message);
   }
     setLoading(false);
   }

   fetchData();
}, []);

Then you can use data[0].price;

CodePudding user response:

You'll probably want to make your individual product into its own component that handles the fetching, and setting the price to a state value that's local to that product view. Here's a full example of how you could do that:

import { useState, useEffect } from "react";

const Product = ({ product }) => {
  const [price, setPrice] = useState("Price loading...");

  useEffect(() => {
    fetch("https://---/test.php?id="   product.productid   "/", {
      method: "GET"
    })
      .then((response) => response.json())
      .then((data) => {
        setPrice(data[0].price);
      });
  }, [product]);

  return (
    <View>
      <Text
        style={{
          fontSize: FONTS.body3,
          paddingLeft: 10
        }}
      >
        {product.name}
        {price}
      </Text>
    </View>
  );
};

const App = () => {
  const item = {
    products: [
      {
        id: 1,
        name: "test product",
        productid: "73827duf"
      },
      {
        id: 2,
        name: "test product2",
        productid: "734437dde"
      }
    ]
  };

  return (
    <div>
      {item.products.map((product) => (
        <Product key={product.id} product={product} />
      ))}
    </div>
  );
};

Alternatively, you could use Promise.all to get all of the price values before mapping your products:

import { useState, useEffect } from "react";

const App = () => {
  const [item] = useState({
    products: [
      {
        id: 1,
        name: "test product",
        productid: "73827duf"
      },
      {
        id: 2,
        name: "test product2",
        productid: "734437dde"
      }
    ]
  });

  const [products, setProducts] = useState([]);

  useEffect(() => {
    Promise.all(
      item.products.map(async (product) => {
        const response = await fetch(
          `https://---/test.php?id=${product.productid}/`
        );
        const data = await response.json();
        return {
          ...product,
          price: data[0].price
        };
      })
    ).then((products) => setProducts(products));
  }, [item]);

  return (
    <div>
      {products.map((product) => {
        return (
          <View key={product.id}>
            <Text
              style={{
                fontSize: FONTS.body3,
                paddingLeft: 10
              }}
            >
              {product.name}
              {product.price}
            </Text>
          </View>
        );
      })}
    </div>
  );
};
  • Related