Skip to content

How to “flatten” a nested object array in React?

I have an object that contains multiple records in the format below:

["name": 'The Belvedere',
"units":[
    {"unit_num": 1,
    "street": '1234 Main',
    "monthly_rent": 900,
    "lease_expiration" 2021-11-01
    },
    {"unit_num": n,
    "street": 'Some address',
    "monthly_rent": 900,
    "lease_expiration" 2021-11-01
    }
]

For each of the multiple “names”, they have one and only one “units” array and within the “units” array, there will be one to many “unit_num” with an associated “street”. I’m trying to generate a flat table that looks like this.

name street rent lease
The Belvedere 1234 Main 900 2021-11-01
The Belvedere 1235 Main 875 2022-03-21
The Grayson 345 Maple 925 2023-10-31

Currently the code is this: The screen maps the “leases” object and calls the Lease component and passes a single “lease” entry.

return (
    <div className="container">
      <h1>Leases</h1>
      <div className="row justify-content-center mt-5 lease">
        {loading ? (
          <h1>
            <Loader />
          </h1>
        ) : error ? (
          <h1>Error</h1>
        ) : (
          leases.map((lease) => {
            return (
              <div className="col-md-9">
                <Lease lease={lease} />
              </div>
            );
          })
        )}
      </div>
    </div>
  );

And the Lease component prints it to the screen.

return (
    <div>
      <MDBTable hover>
        <MDBTableBody>
          <tr>
            <td>{name}</td>
            <td>{street}</td>
            <td>{monthly_rent}</td>
            <td>{lease_expiration}</td>
          </tr>
        </MDBTableBody>
      </MDBTable>
    </div>
  );

The challenge I’m facing is because I’m iterating the object, I can get each row to display, but they are not in a table, just individual rows on the screen.

But I can’t figure out how to pass the entire dataset object to the Lease component and within that component iterate and then populate and return the filled table, instead of passing the “names” individually.

Any suggestions?

Answer

The Lease component must return the rows and not the whole table, so you have to move the other components of the table to the parent component:

...

return (
    <div className="container">
      <h1>Leases</h1>
      <div className="row justify-content-center mt-5 lease">
        {loading ? (
          <h1>
            <Loader />
          </h1>
        ) : error ? (
          <h1>Error</h1>
        ) : (
          <div className="col-md-9">
            <MDBTable hover>
              <MDBTableHead>
                <tr>
                  <th>name</th>
                  <th>street</th>
                  <th>rent</th>
                  <th>lease</th>
                </tr>
              </MDBTableHead>
              <MDBTableBody>
              {
                leases.map((lease) => {
                  return (
                    <Lease lease={lease} />
                  );
                })
              }
              </MDBTableBody>
            </MDBTable>
          </div>
        )}
      </div>
    </div>
  );

And the Lease component:

...

const rows = lease.units.map((unit, index) => (
  <tr key={index}>
    <td>{lease.name}</td>
    <td>{unit.street}</td>
    <td>{unit.monthly_rent}</td>
    <td>{unit.lease_expiration}</td>
  </tr>
))

return (
  <>
    {rows}
  </>
);