如何实现支持多数据结构与布局的可复用React Table组件?
可复用Table组件的TypeScript问题解决
背景
我正在开发一个包含大量表格的应用,这些表格外观大致相同,但部分表格的列配置、单元格内容存在差异,希望实现一个可在全应用复用的Table组件。目前已实现一个接收子组件和tableType的表格包装组件,根据tableType渲染列,但因数据结构和布局差异仍需为不同表格单独开发组件。不想过度使用条件渲染(如{tableType === "first" ? <TableCell>{item.name}</TableCell> : null}),因为这会导致代码难以维护和阅读。采用getCellComponent(tableType, value)类方案后效果很好,但遇到两个TypeScript错误需要解决。
问题1:为columnObj中的payload指定类型
场景
希望将columns props存储在变量中,但不知该为payload指定什么类型:
const columnObj = { firstName: { name: "First Name", width: "25%", accessor: (payload: any) => ( <> <Avatar /> {payload.who.nickname} </> ) }, // ...其他列配置 };
解决方案
- 先定义行数据的具体类型,比如针对该示例的业务数据结构:
// 定义嵌套的数据类型 interface UserInfo { nickname: string; // 补充其他需要的字段 } // 定义单条行数据的类型 interface PayloadType { who: UserInfo; // 补充行数据的其他字段 }
- 定义列配置的通用类型,让列的
accessor参数类型与表格行数据类型关联:
interface ColumnConfig<T> { name: string; width?: string; accessor: (rowData: T) => React.ReactNode; } type Columns<T> = Record<string, ColumnConfig<T>>;
- 为
columnObj指定类型,TypeScript会自动校验accessor中的payload属性:
const columnObj: Columns<PayloadType> = { firstName: { name: "First Name", width: "25%", accessor: (payload) => ( <> <Avatar /> {payload.who.nickname} </> ) }, // ...其他列配置 };
问题2:修复行点击事件的TS错误
场景
想为表格添加行点击事件,通过onClick传递处理函数,但组件内绑定时报TS错误:
// 父组件调用 <MyTable<PayloadType2> columns={columnObj} payload={secondTableData} onClick={(id) => console.log("Row clicked:", id)} /> // 子组件内绑定代码 <TableBody> {payload.map((rowData, index) => { return ( <TableRow key={index} onClick={(id) => props.onClick(rowData.id)}> // 此处报TS错误 // ...单元格渲染逻辑 </TableRow> ); })} </TableBody>
解决方案
- 先在
MyTable组件的Props类型中明确onClick的类型,关联行数据的ID字段类型:
interface MyTableProps<T> { columns: Columns<T>; payload: T[]; onClick?: (rowId: T['id']) => void; // 假设行数据中存在id字段,取其类型 }
- 修正子组件内的
onClick绑定:TableRow的onClick事件参数是React.MouseEvent,不是行ID,所以需要调整事件处理逻辑:
<TableRow key={index} onClick={() => props.onClick?.(rowData.id)} > // ...单元格渲染逻辑 </TableRow>
如果需要传递事件对象,可改为:
<TableRow key={index} onClick={(e) => props.onClick?.(rowData.id, e)} > // ...单元格渲染逻辑 </TableRow>
注意:需确保PayloadType2中确实包含id字段,若实际字段名不同,将T['id']替换为对应字段(如T['userId'])。
内容的提问来源于stack exchange,提问作者qweezz
相关产品推荐
相关产品推荐

