tanstack-table

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

TanStack Table

TanStack Table

Version: @tanstack/react-table@latest Requires: React 16.8+, TypeScript recommended
版本: @tanstack/react-table@latest 要求: React 16.8+,推荐使用TypeScript

Quick Setup

快速开始

bash
npm install @tanstack/react-table
tsx
import {
  useReactTable,
  getCoreRowModel,
  flexRender,
  createColumnHelper,
} from '@tanstack/react-table'

type User = {
  name: string
  age: number
  status: string
}

const columnHelper = createColumnHelper<User>()

const columns = [
  columnHelper.accessor('name', { header: 'Name' }),
  columnHelper.accessor('age', { header: 'Age' }),
  columnHelper.accessor('status', { header: 'Status' }),
  columnHelper.display({
    id: 'actions',
    cell: (props) => <button onClick={() => edit(props.row.original)}>Edit</button>,
  }),
]

function App() {
  const [data] = useState<User[]>([]) // must be stable reference

  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
  })

  return (
    <table>
      <thead>
        {table.getHeaderGroups().map((headerGroup) => (
          <tr key={headerGroup.id}>
            {headerGroup.headers.map((header) => (
              <th key={header.id}>
                {flexRender(header.column.columnDef.header, header.getContext())}
              </th>
            ))}
          </tr>
        ))}
      </thead>
      <tbody>
        {table.getRowModel().rows.map((row) => (
          <tr key={row.id}>
            {row.getVisibleCells().map((cell) => (
              <td key={cell.id}>
                {flexRender(cell.column.columnDef.cell, cell.getContext())}
              </td>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
  )
}
bash
npm install @tanstack/react-table
tsx
import {
  useReactTable,
  getCoreRowModel,
  flexRender,
  createColumnHelper,
} from '@tanstack/react-table'

type User = {
  name: string
  age: number
  status: string
}

const columnHelper = createColumnHelper<User>()

const columns = [
  columnHelper.accessor('name', { header: 'Name' }),
  columnHelper.accessor('age', { header: 'Age' }),
  columnHelper.accessor('status', { header: 'Status' }),
  columnHelper.display({
    id: 'actions',
    cell: (props) => <button onClick={() => edit(props.row.original)}>Edit</button>,
  }),
]

function App() {
  const [data] = useState<User[]>([]) // must be stable reference

  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
  })

  return (
    <table>
      <thead>
        {table.getHeaderGroups().map((headerGroup) => (
          <tr key={headerGroup.id}>
            {headerGroup.headers.map((header) => (
              <th key={header.id}>
                {flexRender(header.column.columnDef.header, header.getContext())}
              </th>
            ))}
          </tr>
        ))}
      </thead>
      <tbody>
        {table.getRowModel().rows.map((row) => (
          <tr key={row.id}>
            {row.getVisibleCells().map((cell) => (
              <td key={cell.id}>
                {flexRender(cell.column.columnDef.cell, cell.getContext())}
              </td>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
  )
}

Row Models (Import Only What You Need)

行模型(仅导入所需模块)

TanStack Table is modular. Only import the row models you actually use:
tsx
import {
  getCoreRowModel,      // required
  getSortedRowModel,    // client-side sorting
  getFilteredRowModel,  // client-side filtering
  getPaginationRowModel,// client-side pagination
  getExpandedRowModel,  // expanding/sub-rows
  getGroupedRowModel,   // grouping + aggregation
  getFacetedRowModel,   // faceted values
  getFacetedUniqueValues,
  getFacetedMinMaxValues,
} from '@tanstack/react-table'
Pipeline order: Core -> Filtered -> Grouped -> Sorted -> Expanded -> Paginated -> Rendered
TanStack Table采用模块化设计。仅导入实际使用的行模型:
tsx
import {
  getCoreRowModel,      // required
  getSortedRowModel,    // client-side sorting
  getFilteredRowModel,  // client-side filtering
  getPaginationRowModel,// client-side pagination
  getExpandedRowModel,  // expanding/sub-rows
  getGroupedRowModel,   // grouping + aggregation
  getFacetedRowModel,   // faceted values
  getFacetedUniqueValues,
  getFacetedMinMaxValues,
} from '@tanstack/react-table'
执行顺序:Core -> Filtered -> Grouped -> Sorted -> Expanded -> Paginated -> Rendered

Rule Categories

规则分类

PriorityCategoryRule FileImpact
CRITICALTable Setup
rules/table-setup.md
Correct table creation, stable data references
CRITICALColumn Definitions
rules/col-column-defs.md
Data model, rendering, type safety
CRITICALRow Models
rules/rm-row-models.md
Modular imports, pipeline order
HIGHSorting
rules/sort-sorting.md
Client/server sorting, custom sort functions
HIGHColumn Filtering
rules/filt-column-filtering.md
Per-column filters, custom filter functions
HIGHGlobal Filtering
rules/filt-global-filtering.md
Table-wide search, global filter function
HIGHPagination
rules/pag-pagination.md
Client/server pagination, page state
MEDIUMRow Selection
rules/sel-row-selection.md
Checkbox/radio selection, selection state
MEDIUMColumn Visibility
rules/vis-column-visibility.md
Show/hide columns dynamically
MEDIUMColumn Sizing
rules/size-column-sizing.md
Widths, resizing, performance
LOWExpanding
rules/exp-expanding.md
Sub-rows, detail panels, hierarchical data
优先级分类规则文件影响
CRITICAL表格设置
rules/table-setup.md
正确创建表格,稳定的数据引用
CRITICAL列定义
rules/col-column-defs.md
数据模型、渲染、类型安全
CRITICAL行模型
rules/rm-row-models.md
模块化导入、执行顺序
HIGH排序
rules/sort-sorting.md
客户端/服务端排序、自定义排序函数
HIGH列筛选
rules/filt-column-filtering.md
列级筛选、自定义筛选函数
HIGH全局筛选
rules/filt-global-filtering.md
表格全局搜索、全局筛选函数
HIGH分页
rules/pag-pagination.md
客户端/服务端分页、页面状态
MEDIUM行选择
rules/sel-row-selection.md
复选框/单选框选择、选择状态
MEDIUM列可见性
rules/vis-column-visibility.md
动态显示/隐藏列
MEDIUM列尺寸
rules/size-column-sizing.md
宽度、调整尺寸、性能
LOW展开
rules/exp-expanding.md
子行、详情面板、层级数据

Critical Rules

关键规则

Always Do

必做事项

  • Stable
    data
    reference
    — use
    useState
    ,
    useMemo
    , or define outside component to prevent infinite re-renders
  • Use
    createColumnHelper<TData>()
    — for maximum type safety in column definitions
  • Import only needed row models — don't import
    getSortedRowModel
    if you don't sort client-side
  • Use
    flexRender
    — for rendering header/cell/footer templates from column defs
  • Use
    getVisibleCells()
    — not
    getAllCells()
    , to respect column visibility
  • Use
    getRowModel()
    — the final row model that applies all features (filtering, sorting, pagination)
  • Control state with
    state
    +
    on*Change
    — for sorting, filtering, pagination, selection, etc.
  • 稳定的
    data
    引用
    — 使用
    useState
    useMemo
    或在组件外部定义,以避免无限重渲染
  • 使用
    createColumnHelper<TData>()
    — 为列定义提供最大程度的类型安全
  • 仅导入所需的行模型 — 如果不使用客户端排序,请勿导入
    getSortedRowModel
  • 使用
    flexRender
    — 从列定义中渲染表头/单元格/页脚模板
  • 使用
    getVisibleCells()
    — 而非
    getAllCells()
    ,以遵循列可见性设置
  • 使用
    getRowModel()
    — 最终应用所有功能(筛选、排序、分页)的行模型
  • 通过
    state
    +
    on*Change
    控制状态
    — 用于排序、筛选、分页、选择等功能

Never Do

禁止事项

  • Define
    data
    inline
    useReactTable({ data: fetchData() })
    causes infinite re-renders
  • Define
    columns
    inside render
    — columns array must be stable (define outside component or
    useMemo
    )
  • Use
    getAllCells()
    for rendering
    — ignores column visibility; use
    getVisibleCells()
  • Mix
    initialState
    and
    state
    for the same feature
    state
    overrides
    initialState
  • Use client-side row models with
    manual*
    options
    — if
    manualSorting: true
    , don't import
    getSortedRowModel
  • Forget
    getRowId
    — without it, row IDs default to index, breaking selection state across re-fetches
  • 内联定义
    data
    useReactTable({ data: fetchData() })
    会导致无限重渲染
  • 在渲染函数内定义
    columns
    — 列数组必须保持稳定(在组件外部定义或使用
    useMemo
  • 使用
    getAllCells()
    进行渲染
    — 会忽略列可见性设置;请使用
    getVisibleCells()
  • 为同一功能混合使用
    initialState
    state
    state
    会覆盖
    initialState
  • 在启用
    manual*
    选项时使用客户端行模型
    — 如果设置
    manualSorting: true
    ,请勿导入
    getSortedRowModel
  • 忘记设置
    getRowId
    — 不设置的话,行ID默认使用索引,会导致重新获取数据时选择状态失效

Key Patterns

核心模式

tsx
// Controlled sorting state
const [sorting, setSorting] = useState<SortingState>([])
const table = useReactTable({
  data, columns,
  getCoreRowModel: getCoreRowModel(),
  getSortedRowModel: getSortedRowModel(),
  state: { sorting },
  onSortingChange: setSorting,
})
// Header click handler
<th onClick={header.column.getToggleSortingHandler()}>
  {flexRender(header.column.columnDef.header, header.getContext())}
  {{ asc: ' 🔼', desc: ' 🔽' }[header.column.getIsSorted() as string] ?? ''}
</th>

// Server-side pagination
const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 })
const table = useReactTable({
  data, columns,
  getCoreRowModel: getCoreRowModel(),
  manualPagination: true,
  rowCount: serverData.totalRows,
  state: { pagination },
  onPaginationChange: setPagination,
})

// Row selection with checkbox column
columnHelper.display({
  id: 'select',
  header: ({ table }) => (
    <input type="checkbox" checked={table.getIsAllRowsSelected()}
      onChange={table.getToggleAllRowsSelectedHandler()} />
  ),
  cell: ({ row }) => (
    <input type="checkbox" checked={row.getIsSelected()}
      disabled={!row.getCanSelect()}
      onChange={row.getToggleSelectedHandler()} />
  ),
})

// Column filtering
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
const table = useReactTable({
  data, columns,
  getCoreRowModel: getCoreRowModel(),
  getFilteredRowModel: getFilteredRowModel(),
  state: { columnFilters },
  onColumnFiltersChange: setColumnFilters,
})
// Filter input
<input value={column.getFilterValue() ?? ''} onChange={e => column.setFilterValue(e.target.value)} />

// Stable row IDs for selection across re-fetches
const table = useReactTable({
  data, columns,
  getRowId: (row) => row.uuid,
  getCoreRowModel: getCoreRowModel(),
})
tsx
// Controlled sorting state
const [sorting, setSorting] = useState<SortingState>([])
const table = useReactTable({
  data, columns,
  getCoreRowModel: getCoreRowModel(),
  getSortedRowModel: getSortedRowModel(),
  state: { sorting },
  onSortingChange: setSorting,
})
// Header click handler
<th onClick={header.column.getToggleSortingHandler()}>
  {flexRender(header.column.columnDef.header, header.getContext())}
  {{ asc: ' 🔼', desc: ' 🔽' }[header.column.getIsSorted() as string] ?? ''}
</th>

// Server-side pagination
const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 })
const table = useReactTable({
  data, columns,
  getCoreRowModel: getCoreRowModel(),
  manualPagination: true,
  rowCount: serverData.totalRows,
  state: { pagination },
  onPaginationChange: setPagination,
})

// Row selection with checkbox column
columnHelper.display({
  id: 'select',
  header: ({ table }) => (
    <input type="checkbox" checked={table.getIsAllRowsSelected()}
      onChange={table.getToggleAllRowsSelectedHandler()} />
  ),
  cell: ({ row }) => (
    <input type="checkbox" checked={row.getIsSelected()}
      disabled={!row.getCanSelect()}
      onChange={row.getToggleSelectedHandler()} />
  ),
})

// Column filtering
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
const table = useReactTable({
  data, columns,
  getCoreRowModel: getCoreRowModel(),
  getFilteredRowModel: getFilteredRowModel(),
  state: { columnFilters },
  onColumnFiltersChange: setColumnFilters,
})
// Filter input
<input value={column.getFilterValue() ?? ''} onChange={e => column.setFilterValue(e.target.value)} />

// Stable row IDs for selection across re-fetches
const table = useReactTable({
  data, columns,
  getRowId: (row) => row.uuid,
  getCoreRowModel: getCoreRowModel(),
})