0

i have a component that gets all products via fetch. it returns all of the products, but then i use a second fetch to get more data based on what was retrieved with the first fetch:

  const [products, setProducts] = useState([]);
  const [productImages, setProductImages] = useState([]);
  useEffect(() => {
    fetch(state.source.api + "/wp/v2/product")
      .then((response) => response.json())
      .then((data) => {
        setProducts(data); //set state
        //loop through each data to get featured_media number
        data.forEach((item) => {
          //get all urls using featured_media
            fetch(state.source.api + "/wp/v2/media/"+ item.featured_media)
              .then((response) => response.json())
              .then((o) => {
                //get all urls OR store to react State
                console.log(o.source_url)
          });
        })
    });
  }, []);
  console.log(productImages);

I am confused on how to set the values of o.source_url into const [productImages, setProductImages] = useState([]);

Can someone please help me out with this? I can provide more code if that is needed.

kb_
  • 177
  • 2
  • 21

2 Answers2

1

I would suggest you to split it into two useEffects and use async/await instead of the callback hell.

useEffect(() => {
   const fetchData = async () => {
      const response = await fetch(state.source.api + "/wp/v2/product");
      const data = await response.json());
      setProducts(data);
   };

   if (products.length === 0) {
      fetchData();
   }
}

And then listen to the products changes with the second one:

useEffect(() => {
   const fetchUrls = async () => {
      const newProducts = [];
      for (const product of products) {
         const response = await fetch(state.source.api...);
         const url = await response.json();
         newProducts.push({ ...product, url });
      }
         
      setProducts(newProducts);
   };

   fetchUrls();
}, [products]);
kind user
  • 40,029
  • 7
  • 67
  • 77
1

You can achieve this utilising async/await to keep you code as flat as possile

const [products, setProducts] = useState([]);
const [productImages, setProductImages] = useState([]);
  
  const getFeaturedMedia = async ({ featured_media }) => {
     const response = await fetch(state.source.api + "/wp/v2/media/"+ item.featured_media);
     return response.json();
  }

  useEffect(() => {
   (async () => {
    const response = await fetch(state.source.api + "/wp/v2/product");
    const data = await response.json();
    setProducts(data);
    const items = await Promise.all(data.map(getFeaturedMedia));
    setProductImages(items.map(({ source_url }) => source_url);
    })();
  }, []);

  console.log(productImages);
Tareq
  • 5,283
  • 2
  • 15
  • 18
  • I tried this, but it returns the images all in a single array. I'm sorry i probably wasnt clear in my question. But i need to return the image of each product, not just all of the images. so i have the fetch to get all products, but then for each product i need to get the image of that product. – kb_ Sep 25 '20 at 16:05