Home > Software engineering >  How can you use .map (or any other alternative) in React for nested Arrays
How can you use .map (or any other alternative) in React for nested Arrays

Time:08-14

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

enter image description here

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>

  • Related