迁移到 V8 指南

迁移到 V8

TanStack Table V8 是对 React Table v7 的一次重大重写,从头开始使用 TypeScript。您的标记和 CSS 的整体结构/组织将基本保持不变,但许多 API 已被重命名或替换。

显著变化

  • 完全重写为 TypeScript,类型包含在基础包中
  • 移除了插件系统,以支持更多的控制反转
  • 大大扩展和改进了 API(以及固定等新功能)
  • 更好的受控状态管理
  • 更好地支持服务器端操作
  • 完整(但可选)的数据管道控制
  • 与框架无关的核心,以及用于 React、Solid、Svelte、Vue 以及将来可能更多框架的适配器
  • 新的开发工具

安装新版本

TanStack Table 的新版本在 @tanstack 作用域下发布。使用您喜欢的包管理器安装新包:

bash
npm uninstall react-table @types/react-table
npm install @tanstack/react-table
npm uninstall react-table @types/react-table
npm install @tanstack/react-table
tsx
- import { useTable } from 'react-table' // [!code --]
+ import { useReactTable } from '@tanstack/react-table' // [!code ++]
- import { useTable } from 'react-table' // [!code --]
+ import { useReactTable } from '@tanstack/react-table' // [!code ++]

类型现在包含在基础包中,因此您可以删除 @types/react-table 包。

如果需要,您可以保留旧的 react-table 包,以便逐步迁移代码。您应该能够毫无问题地同时使用这两个包来处理不同的表格。

更新表格选项

  • useTable 重命名为 useReactTable
  • 旧的钩子和插件系统已被移除,但它们已被替换为每个功能的可摇树优化的行模型导入。
tsx
- import { useTable, usePagination, useSortBy } from 'react-table'; // [!code --]
+ import { // [!code ++]
+   useReactTable, // [!code ++]
+   getCoreRowModel, // [!code ++]
+   getPaginationRowModel, // [!code ++]
+   getSortedRowModel // [!code ++]
+ } from '@tanstack/react-table'; // [!code ++]

// ...

-   const tableInstance = useTable( // [!code --]
-     { columns,  data }, // [!code --]
-     useSortBy, // [!code --]
-     usePagination, //order of hooks used to matter // [!code --]
-     // etc. // [!code --]
-   ); // [!code --]
+   const tableInstance = useReactTable({ // [!code ++]
+     columns, // [!code ++]
+     data, // [!code ++]
+     getCoreRowModel: getCoreRowModel(), // [!code ++]
+     getPaginationRowModel: getPaginationRowModel(), // [!code ++]
+     getSortedRowModel: getSortedRowModel(), //order doesn't matter anymore! // [!code ++]
+     // etc. // [!code ++]
+   }); // [!code ++]
- import { useTable, usePagination, useSortBy } from 'react-table'; // [!code --]
+ import { // [!code ++]
+   useReactTable, // [!code ++]
+   getCoreRowModel, // [!code ++]
+   getPaginationRowModel, // [!code ++]
+   getSortedRowModel // [!code ++]
+ } from '@tanstack/react-table'; // [!code ++]

// ...

-   const tableInstance = useTable( // [!code --]
-     { columns,  data }, // [!code --]
-     useSortBy, // [!code --]
-     usePagination, //order of hooks used to matter // [!code --]
-     // etc. // [!code --]
-   ); // [!code --]
+   const tableInstance = useReactTable({ // [!code ++]
+     columns, // [!code ++]
+     data, // [!code ++]
+     getCoreRowModel: getCoreRowModel(), // [!code ++]
+     getPaginationRowModel: getPaginationRowModel(), // [!code ++]
+     getSortedRowModel: getSortedRowModel(), //order doesn't matter anymore! // [!code ++]
+     // etc. // [!code ++]
+   }); // [!code ++]
  • 所有 disable* 表格选项都已重命名为 enable* 表格选项。(例如,disableSortBy 现在是 enableSortingdisableGroupBy 现在是 enableGrouping 等)
  • ...

更新列定义

  • accessor 重命名为 accessorKeyaccessorFn(取决于您使用的是字符串还是函数)
  • width、minWidth、maxWidth 重命名为 size、minSize、maxSize
  • 可选地,您��以在每个列定义周围使用新的 createColumnHelper 函数以获得更好的 TypeScript 提示。(如果您愿意,仍然可以只使用列定义数组。)
    • 第一个参数是访问器函数或访问器字符串。
    • 第二个参数是列选项对象。
tsx
const columns = [
-  { // [!code --]
-    accessor: 'firstName', // [!code --]
-    Header: 'First Name', // [!code --]
-  }, // [!code --]
-  { // [!code --]
-    accessor: row => row.lastName, // [!code --]
-    Header: () => <span>Last Name</span>, // [!code --]
-  }, // [!code --]

// 最佳 TypeScript 体验,尤其是在稍后使用 `cell.getValue()` 时
+  columnHelper.accessor('firstName', { //accessorKey // [!code ++]
+    header: 'First Name', // [!code ++]
+  }), // [!code ++]
+  columnHelper.accessor(row => row.lastName, { //accessorFn // [!code ++]
+    header: () => <span>Last Name</span>, // [!code ++]
+  }), // [!code ++]

// 或(如果您愿意)
+ { // [!code ++]
+   accessorKey: 'firstName', // [!code ++]
+   header: 'First Name', // [!code ++]
+ }, // [!code ++]
+ { // [!code ++]
+   accessorFn: row => row.lastName, // [!code ++]
+   header: () => <span>Last Name</span>, // [!code ++]
+ }, // [!code ++]
]
const columns = [
-  { // [!code --]
-    accessor: 'firstName', // [!code --]
-    Header: 'First Name', // [!code --]
-  }, // [!code --]
-  { // [!code --]
-    accessor: row => row.lastName, // [!code --]
-    Header: () => <span>Last Name</span>, // [!code --]
-  }, // [!code --]

// 最佳 TypeScript 体验,尤其是在稍后使用 `cell.getValue()` 时
+  columnHelper.accessor('firstName', { //accessorKey // [!code ++]
+    header: 'First Name', // [!code ++]
+  }), // [!code ++]
+  columnHelper.accessor(row => row.lastName, { //accessorFn // [!code ++]
+    header: () => <span>Last Name</span>, // [!code ++]
+  }), // [!code ++]

// 或(如果您愿意)
+ { // [!code ++]
+   accessorKey: 'firstName', // [!code ++]
+   header: 'First Name', // [!code ++]
+ }, // [!code ++]
+ { // [!code ++]
+   accessorFn: row => row.lastName, // [!code ++]
+   header: () => <span>Last Name</span>, // [!code ++]
+ }, // [!code ++]
]

注意:如果在组件内部定义列,您仍应尝试为列定义提供稳定的标识。这将有助于提高性能并防止不必要的重新渲染。将列定义存储在 useMemouseState 钩子中。

  • 列选项名称更改

    • Header 重命名为 header
    • Cell 重命名为 cell(单元格渲染函数也已更改。请参见下文)
    • Footer 重命名为 footer
    • 所有 disable* 列选项都已重命名为 enable* 列选项。(例如,disableSortBy 现在是 enableSortingdisableGroupBy 现在是 enableGrouping 等)
    • sortType sortingFn
    • ...
  • 自定义单元格渲染器的更改

    • value 重命名为 getValue(在整个升级过程中,不再直接提供值,而是公开一个函数 getValue 来计算值。此更改旨在通过仅在调用 getValue() 时计算值然后缓存它来提高性能。)
    • cell: { isGrouped, isPlaceholder, isAggregated } 现在是 cell: { getIsGrouped, getIsPlaceholder, getIsAggregated }
    • column:基本级别 props 现在是特定于 RT 的。您在定义对象时添加到对象的值现在位于 columnDef 中更深一层。
    • table:传递到 useTable 钩子中的 Props 现在显示在 options 下。

迁移表格标记

  • 使用 flexRender() 代替 cell.render('Cell')column.render('Header') 等。
  • getHeaderPropsgetFooterPropsgetCellPropsgetRowProps 等都已被弃用。
    • TanStack Table 不再提供任何默认的 style 或可访问性属性(如 role)。这些对于您来说仍然很重要,但为了支持与框架无关,必须将其删除。
    • 您需要手动定义 onClick 处理程序,但有新的 get*Handler 帮助程序来简化此操作。
    • 您需要手动定义 key props
    • 如果使用需要它的功能(分组表头、聚合等),则需要手动定义 colSpan prop
tsx
- <th {...header.getHeaderProps()}>{cell.render('Header')}</th> // [!code --]
+ <th colSpan={header.colSpan} key={column.id}> // [!code ++]
+   {flexRender( // [!code ++]
+     header.column.columnDef.header, // [!code ++]
+     header.getContext() // [!code ++]
+   )} // [!code ++]
+ </th> // [!code ++]
- <th {...header.getHeaderProps()}>{cell.render('Header')}</th> // [!code --]
+ <th colSpan={header.colSpan} key={column.id}> // [!code ++]
+   {flexRender( // [!code ++]
+     header.column.columnDef.header, // [!code ++]
+     header.getContext() // [!code ++]
+   )} // [!code ++]
+ </th> // [!code ++]
tsx
- <td {...cell.getCellProps()}>{cell.render('Cell')}</td> // [!code --]
+ <td key={cell.id}> // [!code ++]
+   {flexRender( // [!code ++]
+     cell.column.columnDef.cell, // [!code ++]
+     cell.getContext() // [!code ++]
+   )} // [!code ++]
+ </td> // [!code ++]
- <td {...cell.getCellProps()}>{cell.render('Cell')}</td> // [!code --]
+ <td key={cell.id}> // [!code ++]
+   {flexRender( // [!code ++]
+     cell.column.columnDef.cell, // [!code ++]
+     cell.getContext() // [!code ++]
+   )} // [!code ++]
+ </td> // [!code ++]
tsx
// 在这种情况下,在列定义中
- Header: ({ getToggleAllRowsSelectedProps }) => ( // [!code --]
-   <input type="checkbox" {...getToggleAllRowsSelectedProps()} /> // [!code --]
- ), // [!code --]
- Cell: ({ row }) => ( // [!code --]
-   <input type="checkbox" {...row.getToggleRowSelectedProps()} /> // [!code --]
- ), // [!code --]
+ header: ({ table }) => ( // [!code ++]
+   <Checkbox // [!code ++]
+     checked={table.getIsAllRowsSelected()} // [!code ++]
+     indeterminate={table.getIsSomeRowsSelected()} // [!code ++]
+     onChange={table.getToggleAllRowsSelectedHandler()} // [!code ++]
+   /> // [!code ++]
+ ), // [!code ++]
+ cell: ({ row }) => ( // [!code ++]
+   <Checkbox // [!code ++]
+     checked={row.getIsSelected()} // [!code ++]
+     disabled={!row.getCanSelect()} // [!code ++]
+     indeterminate={row.getIsSomeSelected()} // [!code ++]
+     onChange={row.getToggleSelectedHandler()} // [!code ++]
+   /> // [!code ++]
+ ), // [!code ++]
// 在这种情况下,在列定义中
- Header: ({ getToggleAllRowsSelectedProps }) => ( // [!code --]
-   <input type="checkbox" {...getToggleAllRowsSelectedProps()} /> // [!code --]
- ), // [!code --]
- Cell: ({ row }) => ( // [!code --]
-   <input type="checkbox" {...row.getToggleRowSelectedProps()} /> // [!code --]
- ), // [!code --]
+ header: ({ table }) => ( // [!code ++]
+   <Checkbox // [!code ++]
+     checked={table.getIsAllRowsSelected()} // [!code ++]
+     indeterminate={table.getIsSomeRowsSelected()} // [!code ++]
+     onChange={table.getToggleAllRowsSelectedHandler()} // [!code ++]
+   /> // [!code ++]
+ ), // [!code ++]
+ cell: ({ row }) => ( // [!code ++]
+   <Checkbox // [!code ++]
+     checked={row.getIsSelected()} // [!code ++]
+     disabled={!row.getCanSelect()} // [!code ++]
+     indeterminate={row.getIsSomeSelected()} // [!code ++]
+     onChange={row.getToggleSelectedHandler()} // [!code ++]
+   /> // [!code ++]
+ ), // [!code ++]

其他更改

  • 自定义 filterTypes(现在称为 filterFns)具有新的函数签名,因为它仅返回一个布尔值,指示是否应包含该行。
tsx
- (rows: Row[], id: string, filterValue: any) => Row[] // [!code --]
+ (row: Row, id: string, filterValue: any) => boolean // [!code ++]
- (rows: Row[], id: string, filterValue: any) => Row[] // [!code --]
+ (row: Row, id: string, filterValue: any) => boolean // [!code ++]
  • ...

本指南正在编写中。如果您有时间,请考虑为其做出贡献!