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

如何在Tabulator单元格格式化器中合理渲染React组件

在Tabulator自定义格式化器中使用React组件的优化方案

问题背景

已实现通过自定义格式化器在Tabulator表格列中渲染React组件,但存在资源未清理、性能开销大的问题,相关代码如下:

示例React组件

type ReactThingProps = {
  children: any;
  colour: string;
};

const ReactThing: React.FunctionComponent<ReactThingProps> = ({
  colour,
  children,
}: ReactThingProps) => {
  return <span style={{ backgroundColor: colour }}>{children}</span>;
};

export default ReactThing;

当前自定义格式化器实现

const ReactFormatter = (
  cell: any,
  _formatterParams: object,
  _onRendered: EmptyCallback
) => {
  const reactNode = document.createElement("span");
  const reactRoot = createRoot(reactNode);
  reactRoot.render(
    <ReactThing colour={cell.getValue()}>{cell.getValue()}</ReactThing>
  );
  return reactNode;
};

列配置方式

{ title: "Despised Color", field: "despCol", formatter: ReactFormatter },

问题

  1. 表格采用虚拟DOM机制,单元格可能被销毁,需监听哪个事件执行React根的unmount清理?
  2. 频繁创建、销毁React根有性能损耗,有没有更优的方式在格式化器中引入React组件?

解答

问题1:React根的清理时机

Tabulator的cellDestroyed事件会在单元格被销毁(包括虚拟滚动时移出视口)时触发,可在格式化器中为单元格绑定该事件完成清理:

const ReactFormatter = (
  cell: any,
  _formatterParams: object,
  _onRendered: EmptyCallback
) => {
  const reactNode = document.createElement("span");
  const reactRoot = createRoot(reactNode);
  
  reactRoot.render(
    <ReactThing colour={cell.getValue()}>{cell.getValue()}</ReactThing>
  );

  // 单元格销毁时卸载React根
  cell.on("cellDestroyed", () => {
    reactRoot.unmount();
  });

  return reactNode;
};

问题2:性能优化方案

推荐两种方案避免频繁创建React根:

方案1:使用react-tabulator封装库

直接使用官方适配的react-tabulator库,它原生支持在列定义中传入React组件,自动处理组件的挂载、更新与卸载,完全适配虚拟DOM:

{
  title: "Despised Color",
  field: "despCol",
  cellComponent: (props) => (
    <ReactThing colour={props.cell.getValue()}>{props.cell.getValue()}</ReactThing>
  )
}

方案2:复用React根节点

如果不想引入第三方库,可在单元格DOM上存储已创建的React根实例,数据更新时仅更新组件props,而非重建根:

const ReactFormatter = (
  cell: any,
  _formatterParams: object,
  _onRendered: EmptyCallback
) => {
  let reactNode = cell.getElement().querySelector(".react-cell-container");
  let reactRoot;

  if (!reactNode) {
    // 首次渲染:创建容器与根实例
    reactNode = document.createElement("span");
    reactNode.className = "react-cell-container";
    reactRoot = createRoot(reactNode);
    // 存储根实例到DOM节点
    (reactNode as any).reactRootInstance = reactRoot;

    // 绑定销毁事件
    cell.on("cellDestroyed", () => {
      reactRoot.unmount();
    });
  } else {
    // 复用已有根实例
    reactRoot = (reactNode as any).reactRootInstance;
  }

  // 渲染/更新组件
  reactRoot.render(
    <ReactThing colour={cell.getValue()}>{cell.getValue()}</ReactThing>
  );

  return reactNode;
};

这种方式仅在首次渲染时创建React根,后续仅更新组件props,大幅降低性能开销。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 03:27:48