Basil Nagle
Basil Nagle

Reputation: 51

How can I map through several arrays of objects using JSX in React?

I have some json data:

{
    "shops" : 
        [
            {
                "type" : "Blacksmith/Armoury",
                "items_light_armour" : 
                [
                    "Light Armour",
                    {
                        "id": 1,
                        "item" : "Padded Armour", 
                        "low_price": 15, 
                        "med_price": 20, 
                        "high_price": 30,
                        "available": true,
                        "limited": false,
                        "weight": 8,
                        "blurb": "AC11. Made of quilted layers of cloth and batting."
                    },
//...
//three other objects, as array elements, with a similar set of key/value pairs

The first element (inside the items_light_armour array) is just a string to denote what category each data set is.

What I want to do, is display every single object (apart from its ID and blurb) in a table I have. The table generates new rows for every item mapped through. The problem I have is that it's not mapping out the data as intended.

Here's a picture of what the table looks like at when it first loads: enter image description here

So the data does map to the table, but only the first item in each array of objects. Im honestly unsure of how to get all of the data for each category. Specifically, each category should list all of its items, then a new category would open up, list all of its entries like the first and so on until the end of the array is reached, instead of one from each as displayed above.

Here's how I get my data from the JSON file (above my return block in the component):

//get the json data
    const jsonData = require("../Reference Files/Json Files/shops.json");

Then, I convert it to a const

    const objInnerValues = Object.values(jsonData.shops[0])

Then, in the return block of my component, here's how I 'fill' the table rows. EDIT: This is the latest code, following advice from @John:

//...
{
    <>
    objInnerValues.map((things, outerIndex) => (
        {outerIndex === 0 ? console.log("outerIndex WAS 0"): 
        <TableRow key= {outerIndex} onClick={() => BarkItemBlurb(outerIndex)}>

                                        {Object.values(things).map((eachThing, innerIndex) => (      
    {innerIndex == 0 ? console.log("innerIndex or outerIndex was 0"): 
    <>
        <SuperTD key={innerIndex}>{eachThing.item}</SuperTD>    
        <SuperTD key={innerIndex+1}>{eachThing.weight}lbs</SuperTD>  
        <SuperTD key={innerIndex+2}>{eachThing.low_price}gp</SuperTD> 
        <SuperTD key={innerIndex+3}>{eachThing.med_price}gp</SuperTD> 
        <SuperTD key={innerIndex+4}>{eachThing.high_price}gp</SuperTD> 
    </>
    })
    </TableRow>
    })
    </>
}
//...

I'm using styled-components, hence the weird html tag names.

Any advice would be greatly appreciated.

Upvotes: 1

Views: 1091

Answers (2)

Basil Nagle
Basil Nagle

Reputation: 51

Thanks to @John for the assist.

I overcomplicated my design. My JSON file contained arrays and objects, making it awkward to navigate.

After restructuring it to contain only arrays, it was a lot easier.

Also, as for the actual problem, I was shown that I needed to add another map function inside my original one to make it spit the data out the right way.

//...
Object.values(thing).map((innerThing, innerIndex) => (
    <>
        {console.log("\nouter/inner: "+outerIndex +", " +innerIndex)}
        {console.log("\nData: \n\t"+innerThing[2] +"\n\t" +innerThing[8] + "\n\t" +innerThing[3]+"\n\t" + innerThing[4]+"\n\t"+innerThing[5])}
        <TableRow key = {thing[0].toString()}>
            <SuperTD>{innerThing[2]}</SuperTD>
            <SuperTD>{innerThing[8]}lbs</SuperTD>
            <SuperTD>{innerThing[3]}gp</SuperTD>
            <SuperTD>{innerThing[4]}gp</SuperTD>
            <SuperTD>{innerThing[5]}gp</SuperTD>
        </TableRow>
    </>
//...

Now, with the mapping sorted, this is the result: Screenshot showing the desired results

Upvotes: 0

John
John

Reputation: 3775

This is probably want you want. When you get thing, you map that and you don't need to index it because eachThing is the actual object.

{
   objInnerValues.map((things, i) => (
     
       {things.map((eachThing) => (
        <TableRow key= {i} onClick={() => BarkItemBlurb(i)}>  
          <SuperTD>{eachThing.item}</SuperTD>
          <SuperTD>{eachThing.weight}lbs</SuperTD>
          <SuperTD>{eachThing.low_price}gp</SuperTD>
          <SuperTD>{eachThing.med_price}gp</SuperTD>
          <SuperTD>{eachThing.high_price}gp</SuperTD>
       </TableRow>
       )}
    ))}

Given I haven't ran this due to lack of working code; I may have the wrong number of brackets/closing brackets and may have it in the wrong place but overall it should guide you to a solution.

Upvotes: 1

Related Questions