You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为React可复用表格组件配置动态Row类型?

实现支持动态rows类型的可复用TableRowsComponent组件

核心方案是利用TypeScript泛型特性,让组件的rows类型可以根据使用场景动态传入,同时保证headings与rows的类型匹配,避免类型错误。

修改后的完整代码

import { TableCell, TableRow } from "@mui/material";
import TableCellOperations from "./table-cell-operations.componenet";

// 泛化表头类型,让id严格对应行数据的键
export interface HeadingsTypes<RowsType> {
  id: keyof RowsType;
  title: string;
  label: string;
}

// 定义泛型Props接口
interface Props<RowsType> {
  rows?: RowsType[];
  headings: HeadingsTypes<RowsType>[];
}

// 泛型组件,约束行数据必须包含id字段(用于TableRow的key)
const TableRowsComponent = <RowsType extends { id: string | number }>({ rows, headings }: Props<RowsType>) => {
  return (
    <>
      {rows?.map((row) => (
        <TableRow key={row.id}>
          {headings.map((heading) => (
            <TableCell key={String(heading.id)} align="center">
              {typeof row[heading.id] === "object" && row[heading.id] !== null
                ? (row[heading.id] as { title?: string })?.title
                : heading.id === "status"
                ? (row as { status?: number }).status == 0
                  ? "منقضی"
                  : "فعال"
                : row[heading.id]}
            </TableCell>
          ))}
          <TableCellOperations />
        </TableRow>
      ))}
    </>
  );
};

export default TableRowsComponent;

关键修改说明

  1. 泛型参数约束:组件定义时添加<RowsType extends { id: string | number }>,确保所有传入的行数据都包含id字段(作为TableRow的唯一标识)。
  2. 表头类型关联:将HeadingsTypes的id类型改为keyof RowsType,这样表头的id只能是行数据存在的键,避免拼写错误或不匹配的问题。
  3. Props泛化:让rows和headings都依赖泛型参数RowsType,保证两者类型严格匹配。
  4. 特殊逻辑兼容:针对status字段的特殊处理添加了类型断言,避免当行数据不包含status字段时出现类型报错。

使用示例

原PropertyListItem场景

import { PropertyListItem } from "@slice/properties.slice";

<TableRowsComponent<PropertyListItem>
  rows={propertyList}
  headings={[
    { id: "name", title: "名称", label: "名称" },
    { id: "status", title: "状态", label: "状态" },
    // 其他字段...
  ]}
/>

其他类型场景(比如用户数据)

// 定义用户类型
interface User {
  id: string;
  username: string;
  email: string;
  role: string;
}

<TableRowsComponent<User>
  rows={userList}
  headings={[
    { id: "username", title: "用户名", label: "用户名" },
    { id: "email", title: "邮箱", label: "邮箱" },
    { id: "role", title: "角色", label: "角色" },
  ]}
/>

进阶优化:自定义列渲染逻辑

如果需要针对不同类型的列做个性化渲染,可以给HeadingsTypes添加可选的render函数,让调用者灵活控制列内容:

export interface HeadingsTypes<RowsType> {
  id: keyof RowsType;
  title: string;
  label: string;
  render?: (value: RowsType[keyof RowsType], row: RowsType) => React.ReactNode;
}

// 组件内部使用render函数
{heading.render ? heading.render(row[heading.id], row) : (
  typeof row[heading.id] === "object" && row[heading.id] !== null
    ? (row[heading.id] as { title?: string })?.title
    : heading.id === "status"
    ? (row as { status?: number }).status == 0
      ? "منقضی"
      : "فعال"
    : row[heading.id]
)}

调用时自定义渲染:

<TableRowsComponent<User>
  rows={userList}
  headings={[
    { id: "username", title: "用户名", label: "用户名" },
    { 
      id: "role", 
      title: "角色", 
      label: "角色",
      render: (role) => <span className={`role-tag role-${role}`}>{role}</span>
    },
  ]}
/>

内容的提问来源于stack exchange,提问作者Mehrdad Karami Jourabi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 01:12:27