如何处理 TanStack Table 中的一对多关系 (React-Table V8)

Zen*_*r27 14 html-table typescript reactjs react-table react-table-v8

我目前正在尝试Tanstack Table,这是一个很棒的库!

我想做的是建立一个如下所示的表:

我想要的表

我的数据来自以下类型的 API:

type Accounting = {
  category: string;
  total: number; // Sum of all expenses
  expenses: {
    name: string;
    value: number;
  }[];
};
Run Code Online (Sandbox Code Playgroud)

这是我到目前为止所得到的:

const columns = React.useMemo(
    () => [
      columnHelper.accessor("category", {
        header: "Category",
        id: "category",
        cell: (info) => {
          return (
            <>
              {info.row.getCanExpand() && (
                <button
                  {...{
                    onClick: info.row.getToggleExpandedHandler(),
                    style: { cursor: "pointer" },
                    className: "mr-2",
                  }}
                >
                  {info.row.getIsExpanded() ? (
                    <Chevron direction="down" />
                  ) : (
                    <Chevron direction="right" />
                  )}
                </button>
              )}
              {info.getValue()}
            </>
          );
        },
      }),
      columnHelper.accessor("expenses", {
        header: undefined,
        id: "expense-name",
        cell: (info) => {
          // FIXME : this returns a table of objects, I want one row per expense
          return info.getValue();
        },
      }),
      columnHelper.accessor("expenses", {
        aggregationFn: "sum",
        id: "expense-value",
        header: "Expense",
        cell: (info) => {
          // FIXME : this returns a table of objects, I want one row per expense
          return info.getValue();
        },
      }),
    ],
    []
  );

  const grouping = React.useMemo(() => ["category"], []);

  const table = useReactTable({
    data,
    columns,
    state: {
      grouping,
      expanded,
    },
    getExpandedRowModel: getExpandedRowModel(),
    getGroupedRowModel: getGroupedRowModel(),
    getCoreRowModel: getCoreRowModel(),
    onExpandedChange: setExpanded,
    autoResetExpanded: false,
  });
Run Code Online (Sandbox Code Playgroud)

这里的问题是,我在一个类别和该类别的多个费用之间存在一对多关系。

上面的代码不起作用,因为 tanstack 表尝试渲染对象列表(费用列表)。

我还没弄清楚 Tanstack Table 如何处理这个问题?我应该重写某种渲染方法吗?Tanstack Table 是此类数据的不错选择吗?

尊敬。

Lin*_*ste 20

你可以从React Table Expanding Example中得到很多启发。

您缺少的关键部分是getSubRows桌子上的功能。我们不想在父类别中呈现各个费用cell,而是希望在表中为每项费用创建一个新行。

我们的两列是标题和数字。对于顶级Accounting对象,它是category和total。对于个人开支,是name和value。由于这些是不同的属性,我们需要进行一些映射。

让我们从非常简单的开始,为顶级对象定义这两列:

const columns = React.useMemo(
  () => [
    columnHelper.accessor("category", {
      header: "Category",
      id: "category"
    }),
    columnHelper.accessor("total", {
      header: "Expense",
      id: "expense-value"
    })
  ],
  []
);
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


现在,让我们添加扩展功能。(您不需要分组功能。)

我们将expanded状态存储在组件中并将其传递到表,通过onExpandedChange选项同步更改。

我们将在您的表中添加一个新getSubRows选项。这是一个接受父Accounting对象并返回子对象数组的函数Accounting。如前所述,我们需要重命名一些属性以使接口匹配。我们的columns配置需要一个带有category和 的对象total。我在这里设置了一个空数组,expenses因为子行没​​有自己的子行。

const [expanded, setExpanded] = React.useState<ExpandedState>({});

const table = useReactTable({
  data,
  columns,
  state: {
    expanded
  },
  getExpandedRowModel: getExpandedRowModel(),
  getCoreRowModel: getCoreRowModel(),
  onExpandedChange: setExpanded,
  getSubRows: (originalRow) =>
    originalRow.expenses.map((expense) => ({
      category: expense.name,
      total: expense.value,
      expenses: []
    }))
});
Run Code Online (Sandbox Code Playgroud)

对于您的列,我对之前所做的唯一更改是在父行上显示展开/收缩按钮(您在尝试中已经有了)。

const columns = React.useMemo(
  () => [
    columnHelper.accessor("category", {
      header: "Category",
      id: "category",
      cell: (info) => {
        return (
          <>
            {info.row.getCanExpand() && (
              <button onClick={info.row.getToggleExpandedHandler()}>
                {info.row.getIsExpanded() ? "-" : "+"}
              </button>
            )}
            {info.getValue()}
          </>
        );
      }
    }),
    columnHelper.accessor("total", {
      header: "Expense",
      id: "expense-value"
    })
  ],
  []
);
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

现在我们有了功能齐全的行扩展。它并不漂亮,但我会把它留给你来添加样式。

CodeSandbox 演示