rc-table 从零实战:3 个核心类型写出类型安全的 React 表格
【免费下载链接】table📋 Low-level table primitives for React, maintained in the Ant Design ecosystem.项目地址: https://gitcode.com/gh_mirrors/tab/table
自己用 table 标签拼一个 React 表格,光是对齐、固定列、展开行就能吃掉半天;接一个全功能表格库,又常要为用不上的样式和封装买单。@rc-component/table 就是为这个痛点准备的:它是 Ant Design 生态维护的 React 低层表格组件,固定列、展开行、虚拟滚动都内置,API 按 TypeScript 类型优先设计,dataIndex 写错在编译期就能发现。
先建立心智模型:它是"表格原语"
一句话定位:@rc-component/table 负责把数据按列结构渲染成语义正确的 table,排序、筛选、主题这类业务层能力留给你自己组装。它和通用 UI 表格库的差别如下:
| 维度 | 通用 UI 表格库 | @rc-component/table |
|---|---|---|
| 定位 | 开箱即用的业务组件 | 无侵入的表格原语 |
| 样式 | 自带主题与装饰 | 只带必要的基础样式 |
| 扩展方式 | 固定的封装 API | 泛型约束 +components替换任意节点 |
Ant Design 的 Table 就构建在它之上,你在 antd 里看到的固定列、树形数据行为,底层都是这套逻辑。
🚀 三步跑通最小表格
第一步,安装依赖:
npm install @rc-component/table第二步,写一个最小示例。关键是给ColumnsType指定数据泛型:
import Table from '@rc-component/table'; import type { ColumnsType } from '@rc-component/table'; interface User { key: string; name: string; age: number; } const columns: ColumnsType<User> = [ { title: '姓名', dataIndex: 'name', key: 'name', width: 120 }, { title: '年龄', dataIndex: 'age', key: 'age' }, ]; const data: User[] = [ { key: '1', name: 'Jack', age: 28 }, { key: '2', name: 'Rose', age: 36 }, ]; export default () => <Table columns={columns} data={data} />;第三步,渲染它。你会看到一个原生 table:两列数据直接显示,没有多余样式。注意rowKey默认取数据里的key字段,示例数据里已带上。
三个必须理解的核心类型
1. TableProps 的泛型参数
TableProps<RecordType>是整张表的入口类型,定义在 src/Table.tsx。它只暴露一个泛型RecordType,data和columns都由它约束:
// RecordType 确定后,columns 与 data 的类型自动对齐 <Table<User> columns={columns} data={data} rowKey="key" />漏写泛型时,dataIndex 打错字、render 里 record 字段拼错,编译器都会静默放过。这是类型失效最高发的一个点。
2. ColumnsType 与 dataIndex
ColumnsType<RecordType>是普通列与分组列的数组,类型定义在 src/interface.ts。两件事值得记住:dataIndex支持嵌套路径,取深层字段不用手写 render;render签名固定为(value, record, index),record就是完整行数据。
{ title: '城市', dataIndex: ['address', 'city'], // 嵌套路径直接取深层字段 key: 'city', }3. rowKey 与 GetRowKey
行标识决定展开、滚动定位这些功能能否生效。rowKey可以是字段名(默认key),也可以是返回值的函数:
// 数据没有唯一 key 时,用函数合成 rowKey={(record: User) => `${record.dept}-${record.name}`}函数类型即GetRowKey<RecordType>,签名是(record, index?) => Key。
🔩 三个实用模式
模式一:固定列,宽表只锁关键列
场景:管理后台有 10 列,横向滚动时"姓名"要始终可见。要点是三件一套:列上写fixed: 'start'(旧的'left'已废弃)、该列必须有width、表格传scroll.x。
const columns: ColumnsType<User> = [ { title: '姓名', dataIndex: 'name', key: 'name', fixed: 'start', width: 120 }, { title: '部门', dataIndex: 'dept', key: 'dept', width: 160 }, // ... 其余列 ]; <Table columns={columns} data={data} scroll={{ x: 800 }} />存在 fixed 列时,表格会自动切到 fixed 布局,不需要手动设置tableLayout。
模式二:展开行,一个 expandable 对象
场景:点行首图标查看该行详情。所有展开相关配置都收在expandable里,旧的顶层 expandedXxx 属性已废弃:
<Table columns={columns} data={data} expandable={{ expandedRowRender: (record) => <p>{record.detail}</p>, rowExpandable: (record) => record.hasDetail, // 控制哪些行可展开 }} />expandedRowKeys受控和onExpand回调也都从这个对象出,不用额外搭状态。
模式三:万行数据,切到 VirtualTable
场景:一次性渲染两万行会卡死页面,需要虚拟滚动。从同一个包导入VirtualTable,此时scroll的 x、y 必须是数字:
import { VirtualTable } from '@rc-component/table'; <VirtualTable columns={columns} data={rows} listItemHeight={48} // 行高,供虚拟列表做定位 scroll={{ x: 600, y: 400 }} />拿到 ref 后可以scrollTo({ index: 500 })直接跳到第 500 行;注意虚拟模式不支持align: 'center'。
⚠️ 避坑清单:5 个高频问题
| 现象 | 原因 | 处理方式 |
|---|---|---|
| 固定列不锁住,横向滚动时跟着走 | fixed列缺width,或未传scroll.x | 每个 fixed 列设 width,表格传scroll={{ x: 数字 }} |
| dataIndex 打错字,TS 不报错 | ColumnsType没带泛型,RecordType 退化 | 写ColumnsType<User>,并在 Table 上指定泛型 |
| 控制台提示 fixed 取值已废弃 | 还在用旧写法'left'/'right' | 改成'start'/'end' |
| VirtualTable 滚动位置异常 | x 或 y 传了 true、字符串等非数字值 | 两者都传数字;scrollTo 的 align 不用 center |
| 展开行、scrollTo 定位错乱 | 数据没有key字段,而 rowKey 默认取key | 显式设置rowKey字段名或函数 |
落地建议
- 先定
RecordType泛型,再写 columns 和 data;顺序反过来,类型会一路失效; - 固定列三件套(
fixed+width+scroll.x)一次配齐,别分步调试; - 展开、树形数据都依赖稳定 rowKey,合成 key 时保证全局唯一;
- 数据量超过千行再上 VirtualTable,普通表格不必为虚拟滚动多付复杂度。
完整属性与列配置说明见 docs/index.md,类型定义的源头在 src/interface.ts。遇到不确定的字段名,直接查这两处,比翻博客可靠。
【免费下载链接】table📋 Low-level table primitives for React, maintained in the Ant Design ecosystem.项目地址: https://gitcode.com/gh_mirrors/tab/table
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考