名称: tanstack-table 描述: TanStack Table v8 无头数据表格,具有服务器端功能,用于 Cloudflare Workers + D1。用于分页、过滤、排序、虚拟化,或遇到状态管理、TanStack Query 协调、URL 同步错误。 许可证: MIT 允许工具: [Bash, Read, Write, Edit] 元数据: 版本: 1.1.0 作者: Claude Skills Maintainers 最后验证: 2025-12-09 生产测试: true 关键词: - tanstack table - react table - 数据表格 - 数据网格 - 无头表格 - 服务器端分页 - 服务器端过滤 - 服务器端排序 - tanstack query 集成 - cloudflare d1 - cloudflare workers - 虚拟化 - tanstack virtual - 大型数据集 - 表格状态管理 - url 状态同步 - 列配置 - typescript 表格 - react table v8 - 无头 ui - 数据可视化 - 分页 - 过滤 - 排序
TanStack Table 技能
构建生产就绪的无头数据表格,使用 TanStack Table v8,针对服务器端模式和 Cloudflare Workers 集成进行优化。
何时使用此技能
自动触发当您提到:
- “数据表格” 或 “数据网格”
- “服务器端分页” 或 “服务器端过滤”
- “TanStack Table” 或 “React Table”
- “具有大型数据集的表格”
- “通过 API 分页/过滤/排序”
- “Cloudflare D1 表格集成”
- “虚拟化表格” 或 “大型列表性能”
使用此技能当:
- 构建具有分页、过滤或排序的数据表格
- 实现服务器端表格功能(API 驱动)
- 与 TanStack Query 集成进行数据获取
- 处理需要虚拟化的大型数据集(1000+ 行)
- 连接表格到 Cloudflare D1 数据库
- 需要无头表格逻辑而不依赖特定 UI
- 从其他表格库迁移到 TanStack Table v8
此技能提供的内容
1. 生产模板(7个)
- 基本客户端表格 - 简单表格,使用本地数据
- 服务器分页表格 - API 驱动的分页,与 TanStack Query 集成
- D1 数据库集成 - Cloudflare D1 + Workers API + 表格
- 列配置模式 - 类型安全的列定义
- 受控表格状态 - 列可见性、固定、排序、模糊/全局过滤、行选择
- 虚拟化大型数据集 - 使用 TanStack Virtual 进行性能优化
- shadcn/ui 样式表格 - 与 Tailwind v4 + shadcn 集成
2. 服务器端模式
- 与 API 后端的分页
- 使用查询参数的过滤
- 与数据库查询的排序
- 状态管理(页面、过滤器、排序)
- URL 同步
- TanStack Query 协调
3. Cloudflare 集成
- D1 数据库查询模式
- Workers API 端点用于表格数据
- SQL 中的分页 + 过滤 + 排序
- 绑定设置(wrangler.jsonc)
- 客户端集成模式
4. 性能优化
- 使用 TanStack Virtual 进行虚拟化
- 大型数据集渲染(10k+ 行)
- 内存高效模式
- useVirtualizer() 集成
5. 功能控制和用户体验
- 列可见性切换和固定(冻结列)
- 列排序和大小默认值
- 全局 + 模糊搜索和分面过滤器
- 行选择和行固定模式
- 受控状态检查清单以避免性能退化
6. 错误预防
文档和预防 6+ 常见问题:
- 服务器端状态管理混淆
- TanStack Query 集成错误(查询键协调)
- 使用 API 后端的列过滤
- 手动排序设置错误
- URL 状态同步问题
- 大型数据集性能问题
- 过度控制表格状态(columnSizingInfo)导致额外渲染
快速开始
安装
# 核心表格库
bun add @tanstack/react-table@latest
# 可选:用于虚拟化(1000+ 行)
bun add @tanstack/react-virtual@latest
# 可选:用于模糊/全局搜索
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。
基本客户端表格
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: '名称' },
{ accessorKey: 'email', header: '邮箱' },
]
function UsersTable() {
// 关键:使用 useMemo 记忆数据和列,防止无限重新渲染
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>
)
}
服务器端模式(推荐用于大型数据集)
模式 1:使用 TanStack Query 的服务器端分页
Cloudflare Workers API 端点:
// 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 的客户端表格:
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>
)
}
模式 2:服务器端过滤
支持过滤的 API:
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 })
}
客户端:
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,
})
大型数据集的虚拟化
对于 1000+ 行,使用 TanStack Virtual 仅渲染可见行:
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>
)
}
常见错误与解决方案
错误 1:无限重新渲染
问题: 表格无限重新渲染,浏览器冻结。
原因: data 或 columns 引用在每次渲染时变化。
解决方案: 始终使用 useMemo 或 useState:
// ❌ 错误:每次渲染创建新数组引用
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() })
}
错误 2:TanStack Query + 表格状态不匹配
问题: 查询重新获取数据,但分页状态不同步,导致陈旧数据。
解决方案: 在查询键中包含所有表格状态:
// ❌ 错误:查询键中缺少分页
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())
}
})
错误 3:服务器端功能不工作
问题: 分页/过滤/排序不触发 API 调用。
解决方案: 将 manual* 标志设置为 true:
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
// 关键:告诉表格这些是服务器端的
manualPagination: true,
manualFiltering: true,
manualSorting: true,
pageCount: serverPageCount, // 必须提供总页数
})
错误 4:TypeScript “找不到模块” 列辅助
问题: createColumnHelper 的导入错误。
解决方案: 从正确路径导入:
// ❌ 错误:错误路径
import { createColumnHelper } from '@tanstack/table-core'
// ✅ 正确:正确路径
import { createColumnHelper } from '@tanstack/react-table'
// 用法:类型安全的列
const columnHelper = createColumnHelper<User>()
const columns = [
columnHelper.accessor('name', {
header: '名称',
cell: info => info.getValue(), // 完全类型化!
}),
]
错误 5:排序不适用于服务器端
问题: 点击排序表头不更新数据。
解决方案: 在查询键和 API 调用中包含排序:
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,
})
错误 6:大型数据集性能差
问题: 表格在 1000+ 行时缓慢/卡顿。
解决方案: 使用虚拟化(见上方示例)或实现服务器端分页。
与现有技能集成
与 tanstack-query 技能
TanStack Table + TanStack Query 是推荐模式:
// Query 处理数据获取 + 缓存
const { data, isLoading } = useQuery({
queryKey: ['users', tableState],
queryFn: fetchUsers,
})
// Table 处理显示 + 交互
const table = useReactTable({
data: data?.data ?? [],
columns,
getCoreRowModel: getCoreRowModel(),
})
与 cloudflare-d1 技能
// Cloudflare Workers API(来自 cloudflare-d1 技能模式)
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())
})
与 tailwind-v4-shadcn 技能
使用 shadcn/ui 表格组件与 TanStack Table 逻辑:
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>
)
}
最佳实践
1. 始终记忆数据和列
const data = useMemo(() => [...], [依赖项])
const columns = useMemo(() => [...], [])
2. 为大型数据集使用服务器端
- 客户端:<1000 行
- 服务器端:1000+ 行或频繁变化的数据
3. 协调查询键与表格状态
queryKey: ['资源', 分页, 过滤器, 排序]
4. 提供加载状态
if (isLoading) return <表格骨架 />
if (error) return <错误消息 error={error} />
5. 使用列辅助进行类型安全
const columnHelper = createColumnHelper<您的类型>()
const columns = [
columnHelper.accessor('字段', { /* 完全类型化 */ })
]
6. 虚拟化大型客户端表格
if (data.length > 1000) {
// 使用 TanStack Virtual(见上方示例)
}
7. 仅控制所需状态
- 在需要持久化或同步时,保持
排序、分页、过滤器、可见性、固定、排序、选择在受控状态。 - 除非持久化拖动状态,避免控制
columnSizingInfo;它会触发频繁更新并可能影响性能。
模板参考
所有模板在 ~/.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 样式
参考文档
深入指南在 ~/.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 - 受控状态、可见性、固定、排序、模糊/全局过滤、选择
何时加载参考
Claude 应根据用户需求建议加载这些参考文件:
加载 references/common-errors.md 当:
- 用户遇到无限重新渲染或表格冻结
- 查询数据不与分页状态变化同步
- 服务器端功能(分页/过滤/排序)不触发 API 调用
- TypeScript 错误与列辅助导入
- 排序状态变化不更新 API 调用
- 1000+ 行客户端性能问题
- 任何在 6 个文档化问题中提到的错误消息
加载 references/server-side-patterns.md 当:
- 用户询问实现与 API 后端的分页
- 需要构建带后端查询参数的过滤
- 实现与数据库查询的排序
- 构建 Cloudflare Workers 或任何用于表格数据的 API 端点
- 协调表格状态(页面、过滤器、排序)与服务器调用
- 关于 manualPagination、manualFiltering 或 manualSorting 标志的问题
加载 references/query-integration.md 当:
- 协调 TanStack Table + TanStack Query 一起使用
- 查询键和表格状态同步问题
- 当分页/过滤/排序变化时的重新获取模式
- 带表格状态的查询键组合
- 服务器端表格的陈旧数据问题
加载 references/cloudflare-d1-examples.md 当:
- 构建 Cloudflare Workers API 端点用于表格数据
- 编写带分页/过滤的 D1 数据库查询
- 需要完整的端到端 Cloudflare 集成示例
- 表格功能的 SQL 查询模式(LIMIT/OFFSET、WHERE、ORDER BY)
- D1 + 表格的 wrangler.jsonc 绑定设置
加载 references/performance-virtualization.md 当:
- 处理 1000+ 行数据集客户端
- TanStack Virtual 集成问题
- 内存高效渲染模式
- useVirtualizer() 钩子使用
- 大型表格性能优化
- 关于行虚拟化或滚动性能的问题
加载 references/feature-controls.md 当:
- 需要列可见性、固定或排序控制
- 构建工具栏(全局搜索、切换)或将状态同步到 URL/本地存储
- 实现模糊/全局搜索或分面过滤器
- 设置行选择/固定或受控分页/排序
令牌效率
无此技能:
- ~8,000 令牌:研究 v8 变化、服务器端模式、Query 集成
- 3-4 个常见错误遇到
- 30-45 分钟总时间
有此技能:
- ~3,500 令牌:直接模板、错误预防
- 0 错误(所有文档化问题预防)
- 10-15 分钟总时间
节省: ~55-65% 令牌,~70% 时间
生产验证
测试使用:
- React 19.2
- Vite 6.0
- TypeScript 5.8
- Cloudflare Workers(Wrangler 4.0)
- TanStack Query v5.90.7(tanstack-query 技能)
- Tailwind v4 + shadcn/ui(tailwind-v4-shadcn 技能)
堆栈兼容性:
- ✅ Cloudflare Workers + 静态资产
- ✅ Cloudflare D1 数据库
- ✅ TanStack Query 集成
- ✅ React 19.2+ 服务器组件
- ✅ TypeScript 严格模式
- ✅ Vite 6.0+ 构建优化
进一步阅读
- 官方文档: https://tanstack.com/table/latest
- TanStack Virtual: https://tanstack.com/virtual/latest
- GitHub: https://github.com/TanStack/table
- Cloudflare D1 技能:
~/.claude/skills/cloudflare-d1/ - TanStack Query 技能:
~/.claude/skills/tanstack-query/
最后更新: 2025-12-09 技能版本: 1.1.0 库版本: @tanstack/react-table v8.21.3