1

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.

4
  • 1
    Some basic problems: you're iterating over objInnerValues, with i being the index of things. That is: things = objInnerValues[i]. The i value is not an index into things, so using things[i] makes no sense here. Also, don't use "array position" as React's key attribute, as the point of the key attribute is to uniquely identify mapped elements so that React can intelligently update the DOM even if element positions in the array change. Commented Apr 14, 2022 at 15:35
  • @Mike'Pomax'Kamermans Ah ok. So what would a better solution be? Sorry, fairly new to the .map method Commented Apr 14, 2022 at 15:41
  • Also, I used the array position as the index because the array size won't be changing. Commented Apr 14, 2022 at 16:01
  • Doesn't matter: don't teach yourself bad habits =) Key attributes are there to allow React to perform efficient diffing. All you need is a single "sorting would be useful" and now you're actively making React perform bad. Commented Apr 15, 2022 at 1:16

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

5 Comments

Got a bit further thanks to your post, not quite working yet sadly. Ended up using ternary operators to get some control over the flow but its throwing a few confusing errors. Added newer code to my original question
Would it be better if I linked the repo?
Go ahead, I'll look at it in the morning for you.
I've also made an edit where the <TableRow> is inside the inner loop where as before it was outside.
Apologies for taking so long. Had a busy weekend but also wanted to try fixing it myself and, thanks to you, it works! I reworked my JSON file to contain arrays instead of a mix of objects and arrays and it's way easier to work with now. Thanks a tonne for taking the time
0

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

Comments

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.