So I happen to work with an Array that looks like this
Array = [
{
product1,
orderedBy = [{customer1}, {customer2},.....,{customerN}]
},
{
product2,
orderedBy = [{customer3}, {customer4},.....,{customerN}]
},
.
.
.,
{
productN,
orderedBy = [{customer5}, {customer6},.....,{customerN}]
},
]
I want to render it on a table like shown below
I was hoping to achieve something like this, but it gives error
{orders.map((order, index) => (
{order.orderedBy.map((customer, index) => (
<tr>
<td>order.productId</td>
<td>customer.customerId</td>
</tr>
))}
))}
I'm aware that I can create a new array with elements that are easy to render using the map function. However, I'm curious to know if there is any cleaner way to achieve this result that I may not be aware of yet.
CodePudding user response:
Wrap it in either any element such as div
, but since you are filling a table, use <React.Fragment />
, which lets you wrap several children in a faux-element. You can also make it repeat directly inside the <table>
or <tbody>
, if the case applies to you.
Either way, don't forget to add key
to the mapped child:
{orders.map((order, index) => (
<React.Fragment key={'order-' index}>
{order.orderedBy.map((customer, index) => (
<tr key={'customer-' index}>
<td>order.productId</td>
<td>customer.customerId</td>
</tr>
))}
</React.Fragment>
))}
For other cases where you can wrap in a regular element this can also work (can work with any element that accepts and displays children)
{orders.map((order, index) => (
<div key={'order-' index}>
{order.orderedBy.map((customer, index) => (
<tr key={'customer-' index}>
<td>order.productId</td>
<td>customer.customerId</td>
</tr>
))}
</div>
))}
CodePudding user response:
If you compile your data prior to mapping over it you'll have an easier time. This example creates a new object for each customer of product n, and adds it to a new array. You can call compileData
from the JSX, and map
over the returned array of objects instead.
Note: I shifted things around in the data to ensure products and customers have their own id which you should be doing anyway.
function compileData(data) {
const arr = [];
for (const { name: productName, orderedBy } of data) {
for (const { id, name: customerName } of orderedBy) {
arr.push({ id, productName, customerName });
}
}
return arr;
}
function Table({ data }) {
return (
<table>
<thead>
<td>#</td>
<td>Product name</td>
<td>Customer name</td>
</thead>
<tbody>
{compileData(data).map(row => {
return (
<tr key={row.id}>
<td>{row.id}</td>
<td>{row.productName}</td>
<td>{row.customerName}</td>
</tr>
);
})}
</tbody>
</table>
);
}
const data=[{id: 1, name:"product1",orderedBy:[{id: 1, name:"customer1"},{id: 2, name:"customer2"}]},{id: 2, name:"product2",orderedBy:[{id: 3, name:"customer3"},{id: 4, name:"customer4"}]}];
ReactDOM.render(
<Table data={data} />,
document.getElementById('react')
);
table { border-collapse: collapse; }
tr:nth-child(even) { background-color: powderblue; }
td { border: 1px solid #565656; padding: 0.3em; text-transform: capitalize; }
thead { background-color: lightgreen; font-weight: 600; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>