2

I want to display movies row-by-row without changing the data model.

Here's my code:

import * as React from "react";
import { useTable } from "react-table";

const borderStyle = {
  border: "1px dashed navy"
};

export default function App() {
  const data = React.useMemo(
    () => [
      {
        actor: "Johnny Depp",
        movies: [
          {
            name: "Pirates of the Carribean 1"
          },
          {
            name: "Pirates of the Carribean 2"
          },
          {
            name: "Pirates of the Carribean 3"
          },
          {
            name: "Pirates of the Carribean 4"
          }
        ]
      }
    ],
    []
  );
  const columns = React.useMemo(
    () => [
      {
        Header: "Actor",
        accessor: "actor",
      },
      {
        Header: "Movies",
        accessor: (row, index) => {
          console.log({ row });
          // i want to display this row-by-row instead of in 1-row without changing data model
          return row.movies.map(movie => movie.name);
        }
      }
    ],
    []
  );
  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow
  } = useTable({ columns, data });
  return (
    <table {...getTableProps()}>
      <thead>
        {headerGroups.map(headerGroup => (
          <tr {...headerGroup.getHeaderGroupProps()}>
            {headerGroup.headers.map(column => (
              <th {...column.getHeaderProps()} style={borderStyle}>
                {column.render("Header")}
              </th>
            ))}
          </tr>
        ))}
      </thead>
      <tbody {...getTableBodyProps()}>
        {rows.map((row, i) => {
          prepareRow(row);
          if (i == 0) {
            console.log({ row });
          }
          return (
            <tr {...row.getRowProps()}>
              {row.cells.map((cell, j) => {
                if (i == 0 && j < 2) {
                  console.log({ cell, i, j });
                }
                return (
                  <td
                    {...cell.getCellProps()}
                    style={borderStyle}
                  >
                    {cell.render("Cell")}
                  </td>
                );
              })}
            </tr>
          );
        })}
      </tbody>
    </table>
  );
}

It currently looks like:

codesandbox

Here's the direct link to it: https://codesandbox.io/s/modest-sanderson-z0keq?file=/src/App.tsx

My movie list is an array of objects so how will I display it beside actor name? So it looks like:

table

3
  • 1
    Maybe flatten the data could help. Commented May 2, 2020 at 5:55
  • @Nikolaus i thought about that but i feel like this must be built-in since it's too common use-case Commented May 2, 2020 at 6:01
  • @Nikolaus i guess you were right. no other way to do it other than flattening the data as the author himself mentioned :) Commented May 9, 2020 at 7:10

1 Answer 1

2

There is no other way to do it rather than by flattening the data as the author of the library mentioned, so here's how I did it:

import * as React from "react";
import { useTable } from "react-table";

type Data = {
  actor: string;
  movie: string;
}

const borderStyle = {
  border: "1px dashed navy"
};

export default function App() {
  const origData = [
    {
      actor: "Johnny Depp",
      movies: [
        {
          name: "Pirates of the Carribean 1"
        },
        {
          name: "Pirates of the Carribean 2"
        },
        {
          name: "Pirates of the Carribean 3"
        },
        {
          name: "Pirates of the Carribean 4"
        }
      ]
    }
  ];
  const newData: Array<Data> = [];
  origData.forEach(actorObj => {
    actorObj.movies.forEach(movie => {
      newData.push({
        actor: actorObj.actor,
        movie: movie.name
      });
    });
  });
  const data = React.useMemo(() => newData, []);
  const columns = React.useMemo(
    () => [
      {
        Header: "Actor",
        accessor: "actor"
      },
      {
        Header: "Movies",
        accessor: "movie"
      }
    ],
    []
  );
  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow
  } = useTable({ columns, data });
  return (
    <table {...getTableProps()}>
      <thead>
        {headerGroups.map(headerGroup => (
          <tr {...headerGroup.getHeaderGroupProps()}>
            {headerGroup.headers.map(column => (
              <th {...column.getHeaderProps()} style={borderStyle}>
                {column.render("Header")}
              </th>
            ))}
          </tr>
        ))}
      </thead>
      <tbody {...getTableBodyProps()}>
        {rows.map((row, i) => {
          prepareRow(row);
          if (i == 0) {
            console.log({ row });
          }
          return (
            <tr {...row.getRowProps()}>
              {row.cells.map((cell, j) => {
                if (i == 0 && j < 2) {
                  console.log({ cell, i, j });
                }
                return (
                  <td
                    rowSpan={cell.rowSpan}
                    {...cell.getCellProps()}
                    style={borderStyle}
                  >
                    {cell.render("Cell")}
                  </td>
                );
              })}
            </tr>
          );
        })}
      </tbody>
    </table>
  );
}
Sign up to request clarification or add additional context in comments.

Comments

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.