tanstack-table
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTanStack Table Skill
TanStack Table Skill
Build production-ready, headless data tables with TanStack Table v8, optimized for server-side patterns and Cloudflare Workers integration.
使用TanStack Table v8构建可用于生产环境的无头数据表格,该表格针对服务端模式和Cloudflare Workers集成进行了优化。
When to Use This Skill
何时使用本Skill
Auto-triggers when you mention:
- "data table" or "datagrid"
- "server-side pagination" or "server-side filtering"
- "TanStack Table" or "React Table"
- "table with large dataset"
- "paginate/filter/sort with API"
- "Cloudflare D1 table integration"
- "virtualize table" or "large list performance"
Use this skill when:
- Building data tables with pagination, filtering, or sorting
- Implementing server-side table features (API-driven)
- Integrating tables with TanStack Query for data fetching
- Working with large datasets (1000+ rows) needing virtualization
- Connecting tables to Cloudflare D1 databases
- Need headless table logic without opinionated UI
- Migrating from other table libraries to TanStack Table v8
当你提及以下内容时自动触发:
- "数据表格"或"数据网格"
- "服务端分页"或"服务端筛选"
- "TanStack Table"或"React Table"
- "大数据集表格"
- "基于API的分页/筛选/排序"
- "Cloudflare D1表格集成"
- "表格虚拟化"或"大型列表性能"
在以下场景使用本Skill:
- 构建具备分页、筛选或排序功能的数据表格
- 实现服务端表格功能(API驱动)
- 集成TanStack Query进行数据获取
- 处理需要虚拟化的大数据集(1000+行)
- 将表格连接到Cloudflare D1数据库
- 需要无UI偏见的表格逻辑
- 从其他表格库迁移到TanStack Table v8
What This Skill Provides
本Skill提供的内容
1. Production Templates (7)
1. 生产环境模板(7个)
- Basic client-side table - Simple table with local data
- Server-paginated table - API-driven pagination with TanStack Query
- D1 database integration - Cloudflare D1 + Workers API + Table
- Column configuration patterns - Type-safe column definitions
- Controlled table state - Column visibility, pinning, ordering, fuzzy/global filtering, row selection
- Virtualized large dataset - Performance optimization with TanStack Virtual
- shadcn/ui styled table - Integration with Tailwind v4 + shadcn
- 基础客户端表格 - 基于本地数据的简单表格
- 服务端分页表格 - 结合TanStack Query的API驱动分页
- D1数据库集成 - Cloudflare D1 + Workers API + 表格集成
- 列配置模式 - 类型安全的列定义
- 受控表格状态 - 列可见性、固定、排序、模糊/全局筛选、行选择
- 大数据集虚拟化 - 结合TanStack Virtual的性能优化
- shadcn/ui样式化表格 - 与Tailwind v4 + shadcn集成
2. Server-Side Patterns
2. 服务端模式
- Pagination with API backends
- Filtering with query parameters
- Sorting with database queries
- State management (page, filters, sorting)
- URL synchronization
- TanStack Query coordination
- 基于API后端的分页
- 结合查询参数的筛选
- 基于数据库查询的排序
- 状态管理(页码、筛选条件、排序规则)
- URL同步
- TanStack Query协同
3. Cloudflare Integration
3. Cloudflare集成
- D1 database query patterns
- Workers API endpoints for table data
- Pagination + filtering + sorting in SQL
- Bindings setup (wrangler.jsonc)
- Client-side integration patterns
- D1数据库查询模式
- 用于表格数据的Workers API端点
- SQL中的分页+筛选+排序
- 绑定配置(wrangler.jsonc)
- 客户端集成模式
4. Performance Optimization
4. 性能优化
- Virtualization with TanStack Virtual
- Large dataset rendering (10k+ rows)
- Memory-efficient patterns
- useVirtualizer() integration
- 结合TanStack Virtual的虚拟化
- 大数据集渲染(10k+行)
- 内存高效模式
- useVirtualizer()集成
5. Feature Controls & UX
5. 功能控制与用户体验
- Column visibility toggles and pinning (frozen columns)
- Column ordering and sizing defaults
- Global + fuzzy search and faceted filters
- Row selection and row pinning patterns
- Controlled state checklist to avoid perf regressions
- 列可见性切换与固定(冻结列)
- 列排序与默认尺寸设置
- 全局+模糊搜索与分面筛选
- 行选择与行固定模式
- 避免性能退化的受控状态检查清单
6. Error Prevention
6. 错误预防
Documents and prevents 6+ common issues:
- Server-side state management confusion
- TanStack Query integration errors (query key coordination)
- Column filtering with API backends
- Manual sorting setup mistakes
- URL state synchronization issues
- Large dataset performance problems
- Over-controlling table state (columnSizingInfo) causing extra renders
文档并预防6+常见问题:
- 服务端状态管理混淆
- TanStack Query集成错误(查询键协同)
- 基于API后端的列筛选问题
- 手动排序设置错误
- URL状态同步问题
- 大数据集性能问题
- 过度控制表格状态(columnSizingInfo)导致额外重渲染
Quick Start
快速开始
Installation
安装
bash
undefinedbash
undefinedCore table library
核心表格库
bun add @tanstack/react-table@latest
bun add @tanstack/react-table@latest
Optional: For virtualization (1000+ rows)
可选:用于虚拟化(1000+行)
bun add @tanstack/react-virtual@latest
bun add @tanstack/react-virtual@latest
Optional: For fuzzy/global search
可选:用于模糊/全局搜索
bun add @tanstack/match-sorter-utils@latest
**Latest verified versions (as of 2025-12-09):**
- `@tanstack/react-table`: v8.21.3 (stable)
- `@tanstack/react-virtual`: v3.13.12
- `@tanstack/match-sorter-utils`: v8.21.3 (for fuzzy filtering)
**React support:** Works on React 16.8+ through React 19; React Compiler is not supported.bun add @tanstack/match-sorter-utils@latest
**已验证的最新版本(截至2025-12-09):**
- `@tanstack/react-table`: v8.21.3(稳定版)
- `@tanstack/react-virtual`: v3.13.12
- `@tanstack/match-sorter-utils`: v8.21.3(用于模糊筛选)
**React支持:** 兼容React 16.8+至React 19;不支持React Compiler。Basic Client-Side Table
基础客户端表格
typescript
import { useReactTable, getCoreRowModel, ColumnDef } from '@tanstack/react-table'
import { useMemo } from 'react'
interface User {
id: string
name: string
email: string
}
const columns: ColumnDef<User>[] = [
{ accessorKey: 'id', header: 'ID' },
{ accessorKey: 'name', header: 'Name' },
{ accessorKey: 'email', header: 'Email' },
]
function UsersTable() {
// CRITICAL: Memoize data and columns to prevent infinite re-renders
const data = useMemo<User[]>(() => [
{ id: '1', name: 'Alice', email: 'alice@example.com' },
{ id: '2', name: 'Bob', email: 'bob@example.com' },
], [])
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(), // Required
})
return (
<table>
<thead>
{table.getHeaderGroups().map(headerGroup => (
<tr key={headerGroup.id}>
{headerGroup.headers.map(header => (
<th key={header.id}>
{header.isPlaceholder ? null : header.column.columnDef.header}
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map(row => (
<tr key={row.id}>
{row.getVisibleCells().map(cell => (
<td key={cell.id}>
{cell.renderValue()}
</td>
))}
</tr>
))}
</tbody>
</table>
)
}typescript
import { useReactTable, getCoreRowModel, ColumnDef } from '@tanstack/react-table'
import { useMemo } from 'react'
interface User {
id: string
name: string
email: string
}
const columns: ColumnDef<User>[] = [
{ accessorKey: 'id', header: 'ID' },
{ accessorKey: 'name', header: 'Name' },
{ accessorKey: 'email', header: 'Email' },
]
function UsersTable() {
// 关键:对数据和列进行Memo化以防止无限重渲染
const data = useMemo<User[]>(() => [
{ id: '1', name: 'Alice', email: 'alice@example.com' },
{ id: '2', name: 'Bob', email: 'bob@example.com' },
], [])
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}>
{header.isPlaceholder ? null : header.column.columnDef.header}
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map(row => (
<tr key={row.id}>
{row.getVisibleCells().map(cell => (
<td key={cell.id}>
{cell.renderValue()}
</td>
))}
</tr>
))}
</tbody>
</table>
)
}Server-Side Patterns (Recommended for Large Datasets)
服务端模式(推荐用于大数据集)
Pattern 1: Server-Side Pagination with TanStack Query
模式1:结合TanStack Query的服务端分页
Cloudflare Workers API Endpoint:
typescript
// src/routes/api/users.ts
import { Env } from '../../types'
export async function onRequestGet(context: { request: Request; env: Env }) {
const url = new URL(context.request.url)
const page = Number(url.searchParams.get('page')) || 0
const pageSize = Number(url.searchParams.get('pageSize')) || 20
const offset = page * pageSize
// Query D1 database
const { results, meta } = await context.env.DB.prepare(`
SELECT id, name, email, created_at
FROM users
ORDER BY created_at DESC
LIMIT ? OFFSET ?
`).bind(pageSize, offset).all()
// Get total count for pagination
const countResult = await context.env.DB.prepare(`
SELECT COUNT(*) as total FROM users
`).first<{ total: number }>()
return Response.json({
data: results,
pagination: {
page,
pageSize,
total: countResult?.total || 0,
pageCount: Math.ceil((countResult?.total || 0) / pageSize),
},
})
}Client-Side Table with TanStack Query:
typescript
import { useReactTable, getCoreRowModel, PaginationState } from '@tanstack/react-table'
import { useQuery } from '@tanstack/react-query'
import { useState } from 'react'
function ServerPaginatedTable() {
const [pagination, setPagination] = useState<PaginationState>({
pageIndex: 0,
pageSize: 20,
})
// TanStack Query fetches data
const { data, isLoading } = useQuery({
queryKey: ['users', pagination.pageIndex, pagination.pageSize],
queryFn: async () => {
const response = await fetch(
`/api/users?page=${pagination.pageIndex}&pageSize=${pagination.pageSize}`
)
return response.json()
},
})
// TanStack Table manages display
const table = useReactTable({
data: data?.data ?? [],
columns,
getCoreRowModel: getCoreRowModel(),
// Server-side pagination config
manualPagination: true, // CRITICAL: Tell table pagination is manual
pageCount: data?.pagination.pageCount ?? 0,
state: { pagination },
onPaginationChange: setPagination,
})
if (isLoading) return <div>Loading...</div>
return (
<div>
<table>{/* render table */}</table>
{/* Pagination controls */}
<div>
<button
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
Previous
</button>
<span>
Page {table.getState().pagination.pageIndex + 1} of{' '}
{table.getPageCount()}
</span>
<button
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
Next
</button>
</div>
</div>
)
}Cloudflare Workers API端点:
typescript
// src/routes/api/users.ts
import { Env } from '../../types'
export async function onRequestGet(context: { request: Request; env: Env }) {
const url = new URL(context.request.url)
const page = Number(url.searchParams.get('page')) || 0
const pageSize = Number(url.searchParams.get('pageSize')) || 20
const offset = page * pageSize
// 查询D1数据库
const { results, meta } = await context.env.DB.prepare(`
SELECT id, name, email, created_at
FROM users
ORDER BY created_at DESC
LIMIT ? OFFSET ?
`).bind(pageSize, offset).all()
// 获取分页所需的总条数
const countResult = await context.env.DB.prepare(`
SELECT COUNT(*) as total FROM users
`).first<{ total: number }>()
return Response.json({
data: results,
pagination: {
page,
pageSize,
total: countResult?.total || 0,
pageCount: Math.ceil((countResult?.total || 0) / pageSize),
},
})
}结合TanStack Query的客户端表格:
typescript
import { useReactTable, getCoreRowModel, PaginationState } from '@tanstack/react-table'
import { useQuery } from '@tanstack/react-query'
import { useState } from 'react'
function ServerPaginatedTable() {
const [pagination, setPagination] = useState<PaginationState>({
pageIndex: 0,
pageSize: 20,
})
// TanStack Query负责数据获取
const { data, isLoading } = useQuery({
queryKey: ['users', pagination.pageIndex, pagination.pageSize],
queryFn: async () => {
const response = await fetch(
`/api/users?page=${pagination.pageIndex}&pageSize=${pagination.pageSize}`
)
return response.json()
},
})
// TanStack Table负责展示
const table = useReactTable({
data: data?.data ?? [],
columns,
getCoreRowModel: getCoreRowModel(),
// 服务端分页配置
manualPagination: true, // 关键:告知表格分页由服务端处理
pageCount: data?.pagination.pageCount ?? 0,
state: { pagination },
onPaginationChange: setPagination,
})
if (isLoading) return <div>加载中...</div>
return (
<div>
<table>{/* 渲染表格 */}</table>
{/* 分页控件 */}
<div>
<button
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
上一页
</button>
<span>
第 {table.getState().pagination.pageIndex + 1} 页,共 {table.getPageCount()} 页
</span>
<button
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
下一页
</button>
</div>
</div>
)
}Pattern 2: Server-Side Filtering
模式2:服务端筛选
API with Filter Support:
typescript
export async function onRequestGet(context: { request: Request; env: Env }) {
const url = new URL(context.request.url)
const search = url.searchParams.get('search') || ''
const { results } = await context.env.DB.prepare(`
SELECT * FROM users
WHERE name LIKE ? OR email LIKE ?
LIMIT 20
`).bind(`%${search}%`, `%${search}%`).all()
return Response.json({ data: results })
}Client-Side:
typescript
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
const { data } = useQuery({
queryKey: ['users', columnFilters],
queryFn: async () => {
const search = columnFilters.find(f => f.id === 'search')?.value || ''
return fetch(`/api/users?search=${search}`).then(r => r.json())
},
})
const table = useReactTable({
data: data?.data ?? [],
columns,
getCoreRowModel: getCoreRowModel(),
manualFiltering: true, // CRITICAL: Server handles filtering
state: { columnFilters },
onColumnFiltersChange: setColumnFilters,
})支持筛选的API:
typescript
export async function onRequestGet(context: { request: Request; env: Env }) {
const url = new URL(context.request.url)
const search = url.searchParams.get('search') || ''
const { results } = await context.env.DB.prepare(`
SELECT * FROM users
WHERE name LIKE ? OR email LIKE ?
LIMIT 20
`).bind(`%${search}%`, `%${search}%`).all()
return Response.json({ data: results })
}客户端实现:
typescript
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
const { data } = useQuery({
queryKey: ['users', columnFilters],
queryFn: async () => {
const search = columnFilters.find(f => f.id === 'search')?.value || ''
return fetch(`/api/users?search=${search}`).then(r => r.json())
},
})
const table = useReactTable({
data: data?.data ?? [],
columns,
getCoreRowModel: getCoreRowModel(),
manualFiltering: true, // 关键:由服务端处理筛选
state: { columnFilters },
onColumnFiltersChange: setColumnFilters,
})Virtualization for Large Datasets
大数据集虚拟化
For 1000+ rows, use TanStack Virtual to only render visible rows:
typescript
import { useVirtualizer } from '@tanstack/react-virtual'
import { useRef } from 'react'
function VirtualizedTable() {
const tableContainerRef = useRef<HTMLDivElement>(null)
const table = useReactTable({
data: largeDataset, // 10k+ rows
columns,
getCoreRowModel: getCoreRowModel(),
})
const { rows } = table.getRowModel()
// Virtualize rows
const rowVirtualizer = useVirtualizer({
count: rows.length,
getScrollElement: () => tableContainerRef.current,
estimateSize: () => 50, // Row height in px
overscan: 10, // Render 10 extra rows for smooth scrolling
})
return (
<div ref={tableContainerRef} style={{ height: '600px', overflow: 'auto' }}>
<table style={{ height: `${rowVirtualizer.getTotalSize()}px` }}>
<thead>{/* header */}</thead>
<tbody>
{rowVirtualizer.getVirtualItems().map(virtualRow => {
const row = rows[virtualRow.index]
return (
<tr
key={row.id}
style={{
position: 'absolute',
transform: `translateY(${virtualRow.start}px)`,
width: '100%',
}}
>
{row.getVisibleCells().map(cell => (
<td key={cell.id}>{cell.renderValue()}</td>
))}
</tr>
)
})}
</tbody>
</table>
</div>
)
}对于1000+行的数据集,使用TanStack Virtual仅渲染可见行:
typescript
import { useVirtualizer } from '@tanstack/react-virtual'
import { useRef } from 'react'
function VirtualizedTable() {
const tableContainerRef = useRef<HTMLDivElement>(null)
const table = useReactTable({
data: largeDataset, // 10k+行
columns,
getCoreRowModel: getCoreRowModel(),
})
const { rows } = table.getRowModel()
// 对行进行虚拟化
const rowVirtualizer = useVirtualizer({
count: rows.length,
getScrollElement: () => tableContainerRef.current,
estimateSize: () => 50, // 行高(像素)
overscan: 10, // 额外渲染10行以保证滚动流畅
})
return (
<div ref={tableContainerRef} style={{ height: '600px', overflow: 'auto' }}>
<table style={{ height: `${rowVirtualizer.getTotalSize()}px` }}>
<thead>{/* 表头 */}</thead>
<tbody>
{rowVirtualizer.getVirtualItems().map(virtualRow => {
const row = rows[virtualRow.index]
return (
<tr
key={row.id}
style={{
position: 'absolute',
transform: `translateY(${virtualRow.start}px)`,
width: '100%',
}}
>
{row.getVisibleCells().map(cell => (
<td key={cell.id}>{cell.renderValue()}</td>
))}
</tr>
)
})}
</tbody>
</table>
</div>
)
}Common Errors & Solutions
常见问题与解决方案
Error 1: Infinite Re-Renders
问题1:无限重渲染
Problem: Table re-renders infinitely, browser freezes.
Cause: or references change on every render.
datacolumnsSolution: Always use or :
useMemouseStatetypescript
// ❌ BAD: New array reference every render
function Table() {
const data = [{ id: 1 }] // Creates new array!
const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel() })
}
// ✅ GOOD: Stable reference
function Table() {
const data = useMemo(() => [{ id: 1 }], []) // Stable
const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel() })
}
// ✅ ALSO GOOD: Define outside component
const data = [{ id: 1 }]
function Table() {
const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel() })
}问题现象: 表格无限重渲染,浏览器冻结。
原因: 或的引用在每次渲染时发生变化。
datacolumns解决方案: 始终使用或:
useMemouseStatetypescript
// ❌ 错误:每次渲染创建新数组引用
function Table() {
const data = [{ id: 1 }] // 创建新数组!
const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel() })
}
// ✅ 正确:稳定的引用
function Table() {
const data = useMemo(() => [{ id: 1 }], []) // 稳定引用
const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel() })
}
// ✅ 同样正确:在组件外部定义
const data = [{ id: 1 }]
function Table() {
const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel() })
}Error 2: TanStack Query + Table State Mismatch
问题2:TanStack Query + 表格状态不匹配
Problem: Query refetches but pagination state not in sync, causing stale data.
Solution: Include ALL table state in query key:
typescript
// ❌ BAD: Missing pagination in query key
const { data } = useQuery({
queryKey: ['users'], // Doesn't include page!
queryFn: () => fetch(`/api/users?page=${pagination.pageIndex}`).then(r => r.json())
})
// ✅ GOOD: Complete query key
const { data } = useQuery({
queryKey: ['users', pagination.pageIndex, pagination.pageSize, columnFilters, sorting],
queryFn: () => {
const params = new URLSearchParams({
page: pagination.pageIndex.toString(),
pageSize: pagination.pageSize.toString(),
// ... filters, sorting
})
return fetch(`/api/users?${params}`).then(r => r.json())
}
})问题现象: 查询重新获取数据但分页状态不同步,导致数据过期。
解决方案: 将所有表格状态包含在查询键中:
typescript
// ❌ 错误:查询键中缺少分页信息
const { data } = useQuery({
queryKey: ['users'], // 未包含页码!
queryFn: () => fetch(`/api/users?page=${pagination.pageIndex}`).then(r => r.json())
})
// ✅ 正确:完整的查询键
const { data } = useQuery({
queryKey: ['users', pagination.pageIndex, pagination.pageSize, columnFilters, sorting],
queryFn: () => {
const params = new URLSearchParams({
page: pagination.pageIndex.toString(),
pageSize: pagination.pageSize.toString(),
// ... 筛选条件、排序规则
})
return fetch(`/api/users?${params}`).then(r => r.json())
}
})Error 3: Server-Side Features Not Working
问题3:服务端功能无法工作
Problem: Pagination/filtering/sorting doesn't trigger API calls.
Solution: Set flags to :
manual*truetypescript
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
// CRITICAL: Tell table these are server-side
manualPagination: true,
manualFiltering: true,
manualSorting: true,
pageCount: serverPageCount, // Must provide total page count
})问题现象: 分页/筛选/排序不触发API调用。
解决方案: 将标志设置为:
manual*truetypescript
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
// 关键:告知表格这些功能由服务端处理
manualPagination: true,
manualFiltering: true,
manualSorting: true,
pageCount: serverPageCount, // 必须提供总页数
})Error 4: TypeScript "Cannot Find Module" for Column Helper
问题4:TypeScript无法找到Column Helper模块
Problem: Import errors for .
createColumnHelperSolution: Import from correct path:
typescript
// ❌ BAD: Wrong path
import { createColumnHelper } from '@tanstack/table-core'
// ✅ GOOD: Correct path
import { createColumnHelper } from '@tanstack/react-table'
// Usage for type-safe columns
const columnHelper = createColumnHelper<User>()
const columns = [
columnHelper.accessor('name', {
header: 'Name',
cell: info => info.getValue(), // Fully typed!
}),
]问题现象: 导入时出现错误。
createColumnHelper解决方案: 从正确的路径导入:
typescript
// ❌ 错误:路径错误
import { createColumnHelper } from '@tanstack/table-core'
// ✅ 正确:正确路径
import { createColumnHelper } from '@tanstack/react-table'
// 类型安全列的用法
const columnHelper = createColumnHelper<User>()
const columns = [
columnHelper.accessor('name', {
header: 'Name',
cell: info => info.getValue(), // 完全类型化!
}),
]Error 5: Sorting Not Working with Server-Side
问题5:服务端排序无法工作
Problem: Clicking sort headers doesn't update data.
Solution: Include sorting in query key and API call:
typescript
const [sorting, setSorting] = useState<SortingState>([])
const { data } = useQuery({
queryKey: ['users', pagination, sorting], // Include sorting
queryFn: async () => {
const sortParam = sorting[0]
? `&sortBy=${sorting[0].id}&sortOrder=${sorting[0].desc ? 'desc' : 'asc'}`
: ''
return fetch(`/api/users?page=${pagination.pageIndex}${sortParam}`).then(r => r.json())
}
})
const table = useReactTable({
data: data?.data ?? [],
columns,
getCoreRowModel: getCoreRowModel(),
manualSorting: true,
state: { sorting },
onSortingChange: setSorting,
})问题现象: 点击排序表头后数据未更新。
解决方案: 将排序规则包含在查询键和API调用中:
typescript
const [sorting, setSorting] = useState<SortingState>([])
const { data } = useQuery({
queryKey: ['users', pagination, sorting], // 包含排序规则
queryFn: async () => {
const sortParam = sorting[0]
? `&sortBy=${sorting[0].id}&sortOrder=${sorting[0].desc ? 'desc' : 'asc'}`
: ''
return fetch(`/api/users?page=${pagination.pageIndex}${sortParam}`).then(r => r.json())
}
})
const table = useReactTable({
data: data?.data ?? [],
columns,
getCoreRowModel: getCoreRowModel(),
manualSorting: true,
state: { sorting },
onSortingChange: setSorting,
})Error 6: Poor Performance with Large Datasets
问题6:大数据集性能低下
Problem: Table slow/laggy with 1000+ rows.
Solution: Use virtualization (see example above) or implement server-side pagination.
问题现象: 表格在1000+行时缓慢/卡顿。
解决方案: 使用虚拟化(见上方示例)或实现服务端分页。
Integration with Existing Skills
与现有Skill的集成
With tanstack-query Skill
与tanstack-query Skill集成
TanStack Table + TanStack Query is the recommended pattern:
typescript
// Query handles data fetching + caching
const { data, isLoading } = useQuery({
queryKey: ['users', tableState],
queryFn: fetchUsers,
})
// Table handles display + interactions
const table = useReactTable({
data: data?.data ?? [],
columns,
getCoreRowModel: getCoreRowModel(),
})TanStack Table + TanStack Query是推荐的组合模式:
typescript
// Query负责数据获取 + 缓存
const { data, isLoading } = useQuery({
queryKey: ['users', tableState],
queryFn: fetchUsers,
})
// Table负责展示 + 交互
const table = useReactTable({
data: data?.data ?? [],
columns,
getCoreRowModel: getCoreRowModel(),
})With cloudflare-d1 Skill
与cloudflare-d1 Skill集成
typescript
// Cloudflare Workers API (from cloudflare-d1 skill patterns)
export async function onRequestGet({ env }: { env: Env }) {
const { results } = await env.DB.prepare('SELECT * FROM users LIMIT 20').all()
return Response.json({ data: results })
}
// Client-side table consumes D1 data
const { data } = useQuery({
queryKey: ['users'],
queryFn: () => fetch('/api/users').then(r => r.json())
})typescript
// Cloudflare Workers API(来自cloudflare-d1 Skill模式)
export async function onRequestGet({ env }: { env: Env }) {
const { results } = await env.DB.prepare('SELECT * FROM users LIMIT 20').all()
return Response.json({ data: results })
}
// 客户端表格消费D1数据
const { data } = useQuery({
queryKey: ['users'],
queryFn: () => fetch('/api/users').then(r => r.json())
})With tailwind-v4-shadcn Skill
与tailwind-v4-shadcn Skill集成
Use shadcn/ui Table components with TanStack Table logic:
typescript
import { Table, TableHeader, TableBody, TableRow, TableHead, TableCell } from '@/components/ui/table'
function StyledTable() {
const table = useReactTable({ /* config */ })
return (
<Table>
<TableHeader>
{table.getHeaderGroups().map(headerGroup => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map(header => (
<TableHead key={header.id}>
{header.column.columnDef.header}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows.map(row => (
<TableRow key={row.id}>
{row.getVisibleCells().map(cell => (
<TableCell key={cell.id}>
{cell.renderValue()}
</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
)
}将shadcn/ui Table组件与TanStack Table逻辑结合使用:
typescript
import { Table, TableHeader, TableBody, TableRow, TableHead, TableCell } from '@/components/ui/table'
function StyledTable() {
const table = useReactTable({ /* 配置 */ })
return (
<Table>
<TableHeader>
{table.getHeaderGroups().map(headerGroup => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map(header => (
<TableHead key={header.id}>
{header.column.columnDef.header}
</TableHead>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows.map(row => (
<TableRow key={row.id}>
{row.getVisibleCells().map(cell => (
<TableCell key={cell.id}>
{cell.renderValue()}
</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
)
}Best Practices
最佳实践
1. Always Memoize Data and Columns
1. 始终对数据和列进行Memo化
typescript
const data = useMemo(() => [...], [dependencies])
const columns = useMemo(() => [...], [])typescript
const data = useMemo(() => [...], [dependencies])
const columns = useMemo(() => [...], [])2. Use Server-Side for Large Datasets
2. 对大数据集使用服务端模式
- Client-side: <1000 rows
- Server-side: 1000+ rows or frequently changing data
- 客户端模式:<1000行
- 服务端模式:1000+行或频繁变化的数据
3. Coordinate Query Keys with Table State
3. 协调查询键与表格状态
typescript
queryKey: ['resource', pagination, filters, sorting]typescript
queryKey: ['resource', pagination, filters, sorting]4. Provide Loading States
4. 提供加载状态
typescript
if (isLoading) return <TableSkeleton />
if (error) return <ErrorMessage error={error} />typescript
if (isLoading) return <TableSkeleton />
if (error) return <ErrorMessage error={error} />5. Use Column Helper for Type Safety
5. 使用Column Helper保证类型安全
typescript
const columnHelper = createColumnHelper<YourType>()
const columns = [
columnHelper.accessor('field', { /* fully typed */ })
]typescript
const columnHelper = createColumnHelper<YourType>()
const columns = [
columnHelper.accessor('field', { /* 完全类型化 */ })
]6. Virtualize Large Client-Side Tables
6. 对大型客户端表格进行虚拟化
typescript
if (data.length > 1000) {
// Use TanStack Virtual (see example above)
}typescript
if (data.length > 1000) {
// 使用TanStack Virtual(见上方示例)
}7. Control Only the State You Need
7. 仅控制需要的状态
- Keep ,
sorting,pagination,filters,visibility,pinning,orderin controlled state when you must persist or sync.selection - Avoid controlling unless persisting drag state; it triggers frequent updates and can hurt performance.
columnSizingInfo
- 当需要持久化或同步时,将、
sorting、pagination、filters、visibility、pinning、order置于受控状态。selection - 除非需要持久化拖拽状态,否则避免控制;它会触发频繁更新并影响性能。
columnSizingInfo
Templates Reference
模板参考
All templates available in :
~/.claude/skills/tanstack-table/templates/- package.json - Dependencies and versions
- basic-client-table.tsx - Simple client-side table
- server-paginated-table.tsx - Server-side pagination with Query
- d1-database-example.tsx - Cloudflare D1 integration
- column-configuration.tsx - Type-safe column patterns
- controlled-table-state.tsx - Visibility, pinning, ordering, fuzzy/global filtering, selection
- virtualized-large-dataset.tsx - Performance with Virtual
- shadcn-styled-table.tsx - Tailwind v4 + shadcn UI styling
所有模板位于:
~/.claude/skills/tanstack-table/templates/- package.json - 依赖包及版本
- basic-client-table.tsx - 简单客户端表格
- server-paginated-table.tsx - 结合Query的服务端分页
- d1-database-example.tsx - Cloudflare D1集成示例
- column-configuration.tsx - 类型安全列模式
- controlled-table-state.tsx - 可见性、固定、排序、模糊/全局筛选、选择
- virtualized-large-dataset.tsx - 结合Virtual的性能优化
- shadcn-styled-table.tsx - Tailwind v4 + shadcn UI样式
Reference Docs
参考文档
Deep-dive guides in :
~/.claude/skills/tanstack-table/references/- server-side-patterns.md - Pagination, filtering, sorting with APIs
- query-integration.md - Coordinating with TanStack Query
- cloudflare-d1-examples.md - Workers + D1 complete examples
- performance-virtualization.md - TanStack Virtual guide
- common-errors.md - All 6+ documented issues with solutions
- feature-controls.md - Controlled state, visibility, pinning, ordering, fuzzy/global filtering, selection
深度指南位于:
~/.claude/skills/tanstack-table/references/- server-side-patterns.md - 基于API的分页、筛选、排序
- query-integration.md - 与TanStack Query的协同
- cloudflare-d1-examples.md - Workers + D1完整示例
- performance-virtualization.md - TanStack Virtual指南
- common-errors.md - 所有6+已记录问题及解决方案
- feature-controls.md - 受控状态、可见性、固定、排序、模糊/全局筛选、选择
When to Load References
何时加载参考文档
Claude should suggest loading these reference files based on user needs:
Claude会根据用户需求建议加载以下参考文件:
Load references/common-errors.md
when:
references/common-errors.md当以下情况时加载references/common-errors.md
:
references/common-errors.md- User encounters infinite re-renders or table freezing
- Query data not syncing with pagination state changes
- Server-side features (pagination/filtering/sorting) not triggering API calls
- TypeScript errors with column helper imports
- Sorting state changes not updating API calls
- Performance problems with 1000+ rows client-side
- Any error message mentioned in the 6 documented issues
- 用户遇到无限重渲染或表格冻结
- 查询数据与分页状态不同步
- 服务端功能(分页/筛选/排序)不触发API调用
- TypeScript导入Column Helper时出错
- 排序状态变化未更新API调用
- 客户端大数据集性能问题
- 遇到任何已记录的6个问题
Load references/server-side-patterns.md
when:
references/server-side-patterns.md当以下情况时加载references/server-side-patterns.md
:
references/server-side-patterns.md- User asks about implementing pagination with API backends
- Need to build filtering with backend query parameters
- Implementing sorting tied to database queries
- Building Cloudflare Workers or any API endpoints for table data
- Coordinating table state (page, filters, sort) with server calls
- Questions about manualPagination, manualFiltering, or manualSorting flags
- 用户询问如何实现基于API的分页
- 需要构建结合后端查询参数的筛选
- 实现与数据库查询绑定的排序
- 构建Cloudflare Workers或其他API端点用于表格数据
- 协调表格状态(页码、筛选、排序)与服务端调用
- 询问manualPagination、manualFiltering或manualSorting标志
Load references/query-integration.md
when:
references/query-integration.md当以下情况时加载references/query-integration.md
:
references/query-integration.md- Coordinating TanStack Table + TanStack Query together
- Query keys and table state synchronization issues
- Refetch patterns when pagination/filter/sort changes
- Query key composition with table state
- Stale data issues with server-side tables
- 将TanStack Table与TanStack Query结合使用
- 查询键与表格状态同步问题
- 分页/筛选/排序变化时的重新获取模式
- 结合表格状态的查询键组合
- 服务端表格的数据过期问题
Load references/cloudflare-d1-examples.md
when:
references/cloudflare-d1-examples.md当以下情况时加载references/cloudflare-d1-examples.md
:
references/cloudflare-d1-examples.md- Building Cloudflare Workers API endpoints for table data
- Writing D1 database queries with pagination/filtering
- Need complete end-to-end Cloudflare integration examples
- SQL query patterns for table features (LIMIT/OFFSET, WHERE, ORDER BY)
- wrangler.jsonc bindings setup for D1 + table
- 构建用于表格数据的Cloudflare Workers API端点
- 编写带分页/筛选的D1数据库查询
- 需要完整的Cloudflare端到端集成示例
- 表格功能的SQL查询模式(LIMIT/OFFSET、WHERE、ORDER BY)
- D1 + 表格的wrangler.jsonc绑定配置
Load references/performance-virtualization.md
when:
references/performance-virtualization.md当以下情况时加载references/performance-virtualization.md
:
references/performance-virtualization.md- Working with 1000+ row datasets client-side
- TanStack Virtual integration questions
- Memory-efficient rendering patterns
- useVirtualizer() hook usage
- Large table performance optimization
- Questions about row virtualization or scroll performance
- 处理客户端1000+行的数据集
- 询问TanStack Virtual集成
- 内存高效的渲染模式
- useVirtualizer()钩子的使用
- 大型表格的性能优化
- 行虚拟化或滚动性能相关问题
Load references/feature-controls.md
when:
references/feature-controls.md当以下情况时加载references/feature-controls.md
:
references/feature-controls.md- Need column visibility, pinning, or ordering controls
- Building toolbars (global search, toggles) or syncing state to URL/localStorage
- Implementing fuzzy/global search or faceted filters
- Setting up row selection/pinning or controlled pagination/sorting
- 需要列可见性、固定或排序控制
- 构建工具栏(全局搜索、切换)或同步状态到URL/localStorage
- 实现模糊/全局搜索或分面筛选
- 设置行选择/固定或受控分页/排序
Token Efficiency
Token效率
Without this skill:
- ~8,000 tokens: Research v8 changes, server-side patterns, Query integration
- 3-4 common errors encountered
- 30-45 minutes total time
With this skill:
- ~3,500 tokens: Direct templates, error prevention
- 0 errors (all documented issues prevented)
- 10-15 minutes total time
Savings: ~55-65% tokens, ~70% time
不使用本Skill时:
- ~8,000 tokens:研究v8变化、服务端模式、Query集成
- 遇到3-4个常见错误
- 总耗时30-45分钟
使用本Skill时:
- ~3,500 tokens:直接使用模板、错误预防
- 0错误(所有已记录问题均被预防)
- 总耗时10-15分钟
节省: ~55-65% tokens,~70%时间
Production Validation
生产环境验证
Tested with:
- React 19.2
- Vite 6.0
- TypeScript 5.8
- Cloudflare Workers (Wrangler 4.0)
- TanStack Query v5.90.7 (tanstack-query skill)
- Tailwind v4 + shadcn/ui (tailwind-v4-shadcn skill)
Stack compatibility:
- ✅ Cloudflare Workers + Static Assets
- ✅ Cloudflare D1 database
- ✅ TanStack Query integration
- ✅ React 19.2+ server components
- ✅ TypeScript strict mode
- ✅ Vite 6.0+ build optimization
测试环境:
- React 19.2
- Vite 6.0
- TypeScript 5.8
- Cloudflare Workers(Wrangler 4.0)
- TanStack Query v5.90.7(tanstack-query Skill)
- Tailwind v4 + shadcn/ui(tailwind-v4-shadcn Skill)
栈兼容性:
- ✅ Cloudflare Workers + 静态资源
- ✅ Cloudflare D1数据库
- ✅ TanStack Query集成
- ✅ React 19.2+服务端组件
- ✅ TypeScript严格模式
- ✅ Vite 6.0+构建优化
Further Reading
延伸阅读
- Official Docs: https://tanstack.com/table/latest
- TanStack Virtual: https://tanstack.com/virtual/latest
- GitHub: https://github.com/TanStack/table
- Cloudflare D1 Skill:
~/.claude/skills/cloudflare-d1/ - TanStack Query Skill:
~/.claude/skills/tanstack-query/
Last Updated: 2025-12-09
Skill Version: 1.1.0
Library Version: @tanstack/react-table v8.21.3
- 官方文档: https://tanstack.com/table/latest
- TanStack Virtual: https://tanstack.com/virtual/latest
- GitHub: https://github.com/TanStack/table
- Cloudflare D1 Skill:
~/.claude/skills/cloudflare-d1/ - TanStack Query Skill:
~/.claude/skills/tanstack-query/
最后更新: 2025-12-09
Skill版本: 1.1.0
库版本: @tanstack/react-table v8.21.3