首页 > 解决方案 > React Typescript - 来自单个 JSON 的表格中的垂直和水平数据

问题描述

所以,我从一个 API 得到响应,导致一个包含多个对象的数组。结构基本上是:

data = [
    {
        month: 2,
        row1: 1,
        row2: 2,
        row3: 3
    },
    {
        month: 5,
        row1: 4,
        row2: 5,
        row3: 6
    },
    {
        month: 8,
        row1: 7,
        row2: 8,
        row3: 9
    }
]

这些应该呈现在带有row keysas 行标题的日历年表中,并values呈现在匹配的month单元格 (1-12) 中。例如,使用上面的数组:

     | Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov | Dec |
--------------------------------------------------------------------------------
row1 |     |  1  |     |     |  4  |     |     |  7  |     |     |     |     |
row2 |     |  2  |     |     |  5  |     |     |  8  |     |     |     |     |
row3 |     |  3  |     |     |  6  |     |     |  9  |     |     |     |     |

API仅提供具有的对象,因此某些月份列将为空(如上)。这意味着<td></td>当一个月没有值时,我需要渲染一个空的。如果一个月值,那么所有行也有值。

如何在 React(使用 Typescript)中呈现这样的表格?如果需要,可以使用 npm 包。它不一定<table>是,只要我可以将它用作演示文稿的表格即可。

标签: javascriptreactjstypescriptlogic

解决方案


我的方法是稍微重新格式化数据并使用函数来获取数据,如果未定义可以返回回退值。

让我们从在 typescript 中定义我们的类型开始。我假设row1,row2等是实际名称的占位符。所以我们开始的是:

type RowValues = Record<string, number>;

type Raw = RowValues & { month: number };

const data: Raw[] = [/*...*/]

现在让我们将其重新格式化为仅按月份键入的行。我们知道每个月要么有一组完整的行,要么什么都没有。

type Formatted = Record<number, RowValues | undefined>;

const formatted: Formatted = Object.fromEntries( 
  data.map( 
    ({month, ...rows}) => ([month, rows])
  )
);

我没有插入实际的月份名称,但这是我所做的:

export const Table = ({ data }: { data: Raw[] }) => {
  const formatted: Formatted = Object.fromEntries(
    data.map(({ month, ...rows }) => [month, rows])
  );

  const rowKeys = Object.keys(Object.values(formatted)[0] || {});

  const monthNos = [...new Array(12)].map((_, i) => i);

  const getValue = (month: number, row: string): string => {
    const rows = formatted[month];
    return rows ? rows[row].toString() : "";
  };

  return (
    <table>
      <thead>
        <tr>
          <th></th>
          {monthNos.map((i) => (
            <th scope="col">Month #{i}</th>
          ))}
        </tr>
      </thead>
      <tbody>
        {rowKeys.map((key) => (
          <tr key={key}>
            <th scope="row">{key}</th>
            {monthNos.map((i) => (
              <td>{getValue(i, key)}</td>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
  );
};

代码沙盒链接


推荐阅读