1

I have the following data that I want to iterate over:

const publications = [
  {
    id: '1',
    year: '2022-2023',
    period: 'First half',
    title: 'My title',
    authors: 'John Doe',
    type: 'Journal Article',
  },
  {
    id: '2',
    year: '2021-2022',
    period: 'Second half',
    title: 'My second title',
    authors: 'Jane Doe',
    type: 'Book',
  },
  {
    id: '3',
    year: '2022-2023',
    period: 'First half',
    title: 'My third title',
    authors: 'John Smith',
    type: 'Review',
  },
];

I'm trying to produce an MUI table like this:

<TableContainer component={Paper}>
        <TableHead>
          <TableRow>
            {publicationsData.map((item) => (
              <TableCell key={item.id}>{item.name}</TableCell>
            ))}
          </TableRow>
        </TableHead>
        <TableBody>
          {publications.map((publication) => (
            <TableRow key={publication.id}>
              <TableCell>{publication.year}</TableCell>
              <TableCell>{publication.period}</TableCell>
              <TableCell>{publication.title}</TableCell>
              <TableCell>{publication.authors}</TableCell>
              <TableCell>{publication.type}</TableCell>
            </TableRow>
          ))}
        </TableBody>
      </TableContainer>

I put the name of the columns in a separate json file (publicationsData.json)–I want to eliminate this step if possible.

[
  {
    "id": "1",
    "name": "Grant Year"
  },
  {
    "id": "2",
    "name": "Grant Period"
  },
  {
    "id": "3",
    "name": "Title"
  },
  {
    "id": "4",
    "name": "Author(s)"
  },
  {
    "id": "5",
    "name": "Type"
  }
]

I was able to eliminate code duplication in the header with the .map. How do I do the same with the table body? I don't want to manually copy each <TableCell> component.

What's the best way to go about this?

2
  • Why don't you want to manually copy each <TableCell> component? Commented Aug 3, 2022 at 20:26
  • Let's say I have 20+ columns. Is there a solution using .map? Commented Aug 3, 2022 at 20:28

1 Answer 1

2

You can do this using Object.keys.

Try replacing this:

{publications.map((publication) => (
   <TableRow key={publication.id}>
      <TableCell>{publication.year}</TableCell>
      <TableCell>{publication.period}</TableCell>
      <TableCell>{publication.title}</TableCell>
      <TableCell>{publication.authors}</TableCell>
      <TableCell>{publication.type}</TableCell>
   </TableRow>
))}

with this:

{publications.map((publication) => (
  <TableRow key={publication.id}>
    {Object.keys(publication).map((key, index) => (
      <TableCell>{publication[key]}</TableCell>
    ))}
  </TableRow>
))}

This may not be desirable though, since you'll end up with a TableCell for id.

You could prevent this by first filtering the attributes to not include id like this:

  {
    publications.map((publication) => (
      <TableRow key={publication.id}>
        {Object.keys(publication).filter(key => key !== 'id')
          .map((key) => (
            <TableCell>{publication[key]}</TableCell>
          ))}
      </TableRow>
    ));
  }

At this point though, the effort to write cleaner code may be adding more complexity than is worthwhile. There are tradeoffs to every decision, and in this case, writing <TableCell>{...}</TableCell> for several lines in a row (even 20+ lines in a row) might not be the worst thing ever.

It all depends on your exact use-case of course.


Ordering Problem:

As Yone's comment pointed out, this leaves you without a guarantee of the order the keys will be iterated over.

As an alternative, you can create an array of the columns you want in order, like this:

const columns = ["year", "period", "title", "authors", "type"]

And then you can iterate to create your table cells based on that array:

  {
    publications.map((publication) => (
      <TableRow key={publication.id}>
        {columns.map((key) => (
            <TableCell>{publication[key]}</TableCell>
          ))}
      </TableRow>
    ));
  }

This reduces complexity and gives you better control over the columns.

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

3 Comments

make sure you understand the ordering issue stackoverflow.com/questions/5525795/…
Good point @Yone. I just updated with answer with an additional solution which doesn't have the same issue.
Thank you so much for the explanation! True! It's always a trade off. For 10–20 columns, it's probably best to do it manually.

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.