You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Radix UI Table结合Virtuoso虚拟渲染样式异常与报错问题

解决Radix UI Themes Table结合react-virtuoso虚拟滚动的样式错乱与DOM结构报错问题

问题根源

  • <div> cannot appear as a child of <tbody>:TableVirtuoso默认会生成一个<div>容器作为列表外层,而HTML规范中<tbody>的直接子元素只能是<tr>,导致DOM结构非法。
  • <tr> cannot appear as a child of <tr>:默认渲染逻辑下,Virtuoso会额外嵌套行容器,和Radix的<Table.Row>产生嵌套冲突。

解决方案代码

import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
import { Table } from "@radix-ui/themes"
import { useRef } from "react"
import { TableVirtuoso } from 'react-virtuoso';

const TableScrollArea = () => {
    const scrollViewportRef = useRef(null);

    // 生成10000条模拟数据
    const dataArray = Array.from({ length: 10000 }, () => ({
        name: 'AAA',
        email: 'AAA',
        title: 'AAA',
    }));

    const TableRow = ({ person, index }) => {
        return (
            <Table.Row key={`row-${index}`}>
                <Table.RowHeaderCell>{person.name}</Table.RowHeaderCell>
                <Table.Cell>{person.email}</Table.Cell>
                <Table.Cell>{person.title}</Table.Cell>
            </Table.Row>
        )
    }

    return (
        <div className="w-full">
            {/* 固定表头(可选,若不需要固定可合并到滚动容器内) */}
            <Table.Root>
                <Table.Header>
                    <Table.Row>
                        <Table.ColumnHeaderCell>Full name</Table.ColumnHeaderCell>
                        <Table.ColumnHeaderCell>Email</Table.ColumnHeaderCell>
                        <Table.ColumnHeaderCell>Group</Table.ColumnHeaderCell>
                    </Table.Row>
                </Table.Header>
            </Table.Root>

            {/* 虚拟滚动的表体区域 */}
            <ScrollAreaPrimitive.Root className="h-[300px]">
                <ScrollAreaPrimitive.Viewport ref={scrollViewportRef} className="h-full">
                    <Table.Root>
                        <TableVirtuoso
                            data={dataArray}
                            // 自定义组件结构,适配Radix Table的DOM规范
                            components={{
                                TableBody: ({ children }) => <Table.Body>{children}</Table.Body>,
                                Item: ({ children }) => children
                            }}
                            itemContent={(index, person) => <TableRow person={person} index={index} />}
                            customScrollParent={scrollViewportRef.current}
                            // 预估行高,提升虚拟滚动计算精度
                            estimatedItemSize={48}
                        />
                    </Table.Root>
                </ScrollAreaPrimitive.Viewport>
                <ScrollAreaPrimitive.Scrollbar orientation="vertical">
                    <ScrollAreaPrimitive.Thumb />
                </ScrollAreaPrimitive.Scrollbar>
            </ScrollAreaPrimitive.Root>
        </div>
    )
};

export default TableScrollArea

关键修改说明

  1. 自定义Virtuoso组件结构
    通过components属性替换默认容器:

    • TableBody指定为Radix的<Table.Body>,避免生成多余div
    • Item直接返回子元素,消除tr嵌套tr的问题
  2. 滚动容器引用优化
    使用useRef替代useState获取滚动容器,避免状态更新触发不必要的重渲染

  3. 固定表头拆分
    将表头单独抽离到滚动容器外,实现表头固定效果(不需要的话可合并到滚动区域内)

  4. 行高预估与唯一Key
    设置estimatedItemSize帮助Virtuoso更精准计算可视范围;给每行添加唯一Key,避免React渲染警告

修改后即可符合HTML DOM规范,解决报错同时保留Radix Table的原有样式,实现大量数据的流畅虚拟滚动。

内容的提问来源于stack exchange,提问作者Rolando

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 13:02:42