0

My application fetches data from two api endpoints at the same time and combines the data into a single, nested json object like this:

{
"Shop1": [
  {
    "product_name": "Shop 1 Wine", 
    "product_price": "4.99"
  }, 
  {
    "product_name": "Shop1 Wine 2", 
    "product_price": "4.49"
  }
],
"Shop2": [
  {
    "product_name": "Shop 2 Wine", 
    "product_price": "4.99"
  }, 
  {
    "product_name": "Shop 2 Wine 2", 
    "product_price": "4.49"
  }
 ]
}

This is how the data is being fetched by reactjs:

function App() {



const ListLoading = withListLoading(List);
  const [appState, setAppState] = useState({
    loading: false,
    products: null,
  });

  useEffect(() => {
    setAppState({ loading: true });
    const baseUrl = "http://localhost:8080/"
    const searchItem = "wine"
    const shops = [
      "Shop1",
      "Shop2"
    ];
    let urls = [];

    const allUrls = shops.map((shop) => {
      let url = baseUrl + shop + "/" + searchItem;
      urls.push(url)
    });

    function fetchData() {
      const allRequests = urls.map(url =>
        fetch(url).then(response => response.json())
      );
      return Promise.all(allRequests);
    };

    fetchData().then(arrayOfResponses => 
      setAppState({loading: false, products: arrayOfResponses})
    );
  }, [setAppState]);
  return (
    <div className='App'>
      <div className='container'>
        <h1>Products</h1>
      </div>
      <div className='repo-container'>
        <ListLoading isLoading={appState.loading} products={appState.products} />
      </div>
      <footer>
      </footer>
    </div>
  );
}
export default App;

Then in the actual page I have this:

import React from 'react';
const List = (props) => {
  const { products } = props;
  if (!products || products.length === 0) return <p>No products, sorry</p>;
  return (
    <ul>
      <h1>{products}</h1>
      <h2 className='list-head'>products</h2>
      {products.map((product) => {
        return (
          <li className='list'>
            <span className='{product.shop_name}'>{product.product_name} </span>
            <span className='repo-description'>{product.product_price}</span>
          </li>
        );
      })}
    </ul>
  );
};
export default List;

I want to be able to run through each element in the json object and in place of product.shop_name place top level value(like shop1 or shop2) and then in span blocks the values relevant to a given shop(like product_name and product_price).

Currently I'm getting the following error:

Error: Objects are not valid as a React child (found: object with keys {Shop1}). If you meant to render a collection of children, use an array instead..

How can I get react to loop through each level 1 value and then do the same for level 2 values and display them in html?

2
  • Please add what arrayOfResponses looks like. Commented Aug 22, 2020 at 16:17
  • arrayOfResponses is the json object as shown at the top of my question. I can access the data for shop1 by accessing arrayOfResponses[0] Commented Aug 22, 2020 at 16:24

2 Answers 2

1

I think the problem here is in 7 where you try to render array products as jsx child

Probably you mean to write this, if you want Products text as heading

import React from 'react';
const List = (props) => {
 const { products } = props;
 if (!products || products.length === 0) return <p>No products, sorry</p>;
 return (
  <ul>
  <h1>Products</h1>
  <h2 className='list-head'>products</h2>
  {products.map((product) => {
    return (
      <li className='list'>
        <span className='{product.shop_name}'>{product.product_name} </span>
        <span className='repo-description'>{product.product_price}</span>
      </li>
    );
  })}
 </ul>
);
};
export default List;

or if you want to show products response on html do this

import React from 'react';
const List = (props) => {
 const { products } = props;
 if (!products || products.length === 0) return <p>No products, sorry</p>;
 return (
  <ul>
  <h1>{JSON.stringify(products)}</h1>
  <h2 className='list-head'>products</h2>
  {products.map((product) => {
    return (
      <li className='list'>
        <span className='{product.shop_name}'>{product.product_name} </span>
        <span className='repo-description'>{product.product_price}</span>
      </li>
    );
  })}
 </ul>
);
};
export default List;
Sign up to request clarification or add additional context in comments.

1 Comment

Hey Mohit. I mean to got through the json object and display the data accordingly. For example shop_name would display Shop1 and then product_name would display a span block for each item nested inside Shop1, like Shop1 Wine and Shop1 Wine2. Then the code would run through Shop2 and the data nested within it.
1

From your state products. You need to first get the keys since this products is not an array but json object.

so in your render

return(
 <div>
   <h1>Shop1</h1>
     {products.Shop1.map((item,index)=>
        <span>{item.product_name} </span>
        <span>{item.product_price}</span>
     )}

    <h1>Shop2</h1>
    {products.Shop2.map((item,index)=>
       <div key={index}>
          <span>{item.product_name} </span>
          <span>{item.product_price}</span>
       </div>
    )}
  </div>
)

Otherwise you will need to retrieve your data into an array

i.e

[
"Shop1": [
  {
    "product_name": "Shop 1 Wine", 
    "product_price": "4.99"
  }, 
  {
    "product_name": "Shop1 Wine 2", 
    "product_price": "4.49"
  }
],
"Shop2": [
  {
    "product_name": "Shop 2 Wine", 
    "product_price": "4.99"
  }, 
  {
    "product_name": "Shop 2 Wine 2", 
    "product_price": "4.49"
  }
 ]
]

so you would just do

return(
 <div>
     {shops.map((shop,index)=>
        <div>
           <h1>{shop.name}</h1>
            {shop.products.map((product,pos)=>
               <div key={pos}>
                 <span>{product.product_name} </span>
                 <span>{product.product_price}</span>
               </div>
             }
         </div>
     )}
  </div>
)

8 Comments

And what if I don't know the number of Shop objects? Is there a way to loop through it?
Hmm, I keep getting Error: Objects are not valid as a React child (found: object with keys {Shop1}). Is the way I move the object between arrayOfResponses and products incorrect?
Notice that your products is eclosed with { } instead of [ ], so u cannot loop through it as an array until your array of responses return data of type array i.e enclosed with [ ]
I added JSON.stringify(arrayOfResponses) to make the response be enclosed in []. Despite this when I try to run something like {products.Shop.map((item,index)=> I get TypeError: Cannot read property 'map' of undefined, which is weird
Make sure fetchData() returns an array, JSON.stringify(arrayOfResponses) cannot change the data to array
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.