Reputation: 197
I am trying to iterate through an array of objects in reactjs but facing issue. The array basically consists of objects where each object is a row in a table.
Example -
A table like this
| A | B | C |
| 1 | 2 | 3 |
| 4 | 5 | 6 |
would be represented using the following array
[
{"A": 1, "B": 2, "C": 3},
{"A": 4, "B": 5, "C": 6}
]
I am trying to loop through the values using the following syntax -
this.state.data.map(item =>
Object.entries(item).map(([key, value]) =>
<Column field={key} header={key}>{value}</Column>
))
But this gives me the desired table concatenated multiple times. I know there's some issue with the looping but not getting exactly where the difficulty is.
Similar case in python would look like -
for item in array:
for key, value in item.items():
# create a row
Upvotes: 0
Views: 10890
Reputation: 2175
You should consider realigning your way of rendering.
I guess first to get the thead
header of your table which can be done by
<thead>
{Object.keys(this.state.data[0]).map((v) =>
<th>{v}</th>)
}
</thead>
Then after that is the tbody
which can be done by
<tbody>
{this.state.data.map((v) =>
<tr>
{Object.values(v).map((value) => <td>{value}</td>}
</tr>)
}
</tbody>
Reference: https://reactjs.org/docs/thinking-in-react.html
EDIT: You can replace my example of thead
, tbody
, tr
, td
with Grid
,TableHead
,TableBody
, Row
, Column
whichever library components of yours but you get the idea.
Upvotes: 0
Reputation: 1074959
Assuming a Row
component, you'd return a Row
for each callback of the outer map
, something like this (I've put them in a hypothetical Container
just for context):
<Container>
{this.state.data.amp((item, index) =>
<Row key={index}>
{Object.entries(item).map(([key, value]) =>
<Column field={key} header={key} key={key}>{value}</Column>
)}
</Row>
)}
</Container>
Note I've added the key
property, since these are arrays. (Using the index for the key
on Row
is less than ideal. If the item
objects have some unique property you could use instead, that would be better. Using an index is fine if the array never changes during the component lifecycle, but if it does, it can lead to bad renders. More about that in the React documentation.)
But, using Object.entries
on item
is less than ideal, because it relies on the order of the properties in item
, and although JavaScript objects do provide an order for their properties, relying on that order is generally not best practice because the order isn't as simple as it seems and it's really easy to build what seems like the same object but with the properties in a different order.¹ Instead, I suggest having an array of the property names in the order you want them to appear in the columns, and then using that array:
<Container>
{this.state.data.amp((item, index) =>
<Row key={index}>
{propertyNamesInColumnOrder.map(key =>
<Column field={key} header={key} key={key}>{item[key]}</Column>
)}
</Row>
)}
</Container>
¹ "it's really easy to build what seems like the same object but with the properties in a different order" For example:
const obj1 = {a: 1, b: 2};
const obj2 = {b: 2, a: 1};
Those look like the same object. They both have a
and b
properties, and the property values are the same. But the properties are in a different order: obj1
's properties are in the order a, b
, but obj2
's properties are in the order b, a
.
But wait, it gets worse:
const obj3 = {"1": "one", "0": "zero"};
const obj4 = {"0": "zero", "1": "one"};
Surely, if obj1
and obj2
's properties aren't in the same order, then obj3
and obj4
's properties aren't in the same order, right?
Wrong.
They're in the same order, because properties whose names are what the spec calls "array indexes" (canonical numeric Strings whose numeric value is either +0 or a positive integral Number ≤ 232 - 1) are always in numeric order.
Then you throw inherited properties in, and it gets worse still. So again, in general, avoid relying on object property order.
Upvotes: 2