NextJS服务端渲染中使用TanStack v8 cell属性报错求助
解决NextJS服务端组件中TanStack Table v8列定义的cell函数报错问题
问题原因
你遇到的错误是因为:服务端组件(你的Page组件)直接将包含cell渲染函数的columns传递给了客户端组件(TaskTable)。Next.js禁止从服务端往客户端组件直接传递函数,而cell函数属于客户端渲染逻辑(返回React元素、依赖客户端组件如Badge/Button),所以触发了这个限制。
解决方案
方案1:给列定义文件添加'use client'指令
在你的列定义文件顶部加上'use client',明确标记这个文件属于客户端代码:
'use client' import { ColumnDef } from '@tanstack/react-table' // 导入你的Task、TaskStatus、Badge、Button等类型/组件 export const columns: ColumnDef<Task>[] = [ // 你的列定义代码保持不变 ]
同时确保TaskTable组件也标记了'use client'(因为TanStack Table的useReactTable钩子只能在客户端组件中使用):
'use client' import { useReactTable } from '@tanstack/react-table' export const TaskTable = ({ columns, data }) => { const table = useReactTable({ columns, data }) // 表格渲染逻辑... }
方案2:将列定义移到客户端组件内部
如果不想单独维护列定义文件,可以直接在TaskTable组件内部定义columns,让服务端组件只传递数据:
'use client' import { ColumnDef, useReactTable } from '@tanstack/react-table' import { Task, TaskStatus } from './types' import { Badge, Button } from './components' interface TaskTableProps { data: Task[] } export const TaskTable = ({ data }: TaskTableProps) => { // 直接在客户端组件内定义列 const columns: ColumnDef<Task>[] = [ { accessorKey: "task_status", header: "Status", cell: props => { const taskStatus = props.row.getValue("task_status") return ( <Badge className={"cursor-pointer w-full"} customColor={taskStatus.color_task_status}> {taskStatus.name_task_status} </Badge> ) } }, // 其他列定义... ] const table = useReactTable({ columns, data }) // 渲染表格的代码... }
然后修改服务端的Page组件,只传递data即可:
const Page: NextPage = async () => { const tasks = await getTasks() return ( <div className={"w-full max-w-full flex flex-col justify-center items-center"}> <DarkModeToggle/> <h1>Tasks</h1> <div className={"max-w-[90vw]"}> <TaskTable data={tasks}/> {/* 不再传columns */} </div> </div> ); }
方案3:将cell逻辑抽为独立客户端组件
如果需要复用cell逻辑,可以把每个cell的渲染组件单独抽成'use client'标记的文件,然后在列定义中引用:
// StatusCell.tsx - 客户端组件 'use client' import { CellContext } from '@tanstack/react-table' import { Task, TaskStatus } from './types' import { Badge } from './components' export const StatusCell = (props: CellContext<Task, TaskStatus>) => { const taskStatus = props.row.getValue("task_status") return ( <Badge className={"cursor-pointer w-full"} customColor={taskStatus.color_task_status}> {taskStatus.name_task_status} </Badge> ) }
然后在列定义文件(需加'use client')中使用:
'use client' import { ColumnDef } from '@tanstack/react-table' import { StatusCell } from './StatusCell' // 导入其他cell组件... export const columns: ColumnDef<Task>[] = [ { accessorKey: "task_status", header: "Status", cell: StatusCell // 直接引用客户端组件 }, // 其他列... ]
关键注意点
- TanStack Table的
useReactTable是客户端钩子,必须在标记了'use client'的组件中使用。 - 任何包含React元素渲染、客户端组件/钩子的代码,都不能在纯服务端组件中直接传递或执行。
内容的提问来源于stack exchange,提问作者Cigdan
相关产品推荐
相关产品推荐

