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

在Grid.js中使用SolidJS组件遇内存泄漏错误求助

在Grid.js中使用SolidJS组件作为自定义Formatter的正确姿势

我尝试在Grid.js里用自定义Formatter渲染SolidJS组件,但碰到了这个错误:

computations created outside a createRoot or render will never be disposed

我试过参照Grid.js的React适配器写法来实现,但没成功,想知道这种场景下该怎么正确用SolidJS的渲染系统。

问题代码

import { Component, JSXElement, mergeProps } from 'solid-js';

import { Grid, createRef, h } from 'gridjs';
import 'gridjs/dist/theme/mermaid.css';
import { onMount } from 'solid-js';
import { render } from 'solid-js/web';

type Row = [id: number, name: string, age: number];

type Cells<T extends [...any[]]> = {
  [K in keyof T]: {
    data: T[K];
  };
};
type FormatterRow<T extends [...any[]]> = {
  cells: Cells<T>;
};

const NameCell: Component<{ id: Row[0]; name: Row[1] }> = (props) => {
  return <a href={`/user/${props.id}`}>{props.name}</a>;
};

const Wrapper: Component<{ element: JSXElement; parent?: string }> = (
  rawProps
) => {
  const props = mergeProps({ parent: 'div' }, rawProps);

  const ref = createRef();

  onMount(() => {
    render(() => props.element, ref.current);
  });

  return h(props.parent, { ref });
};

const wrap = (element: JSXElement, parent?: string) => {
  return h(Wrapper, { element, parent });
};

const Table: Component<{ rows: Row[] }> = (props) => {
  let gridRef!: HTMLDivElement;

  const grid = new Grid({
    columns: [
      { name: 'Id', hidden: true },
      {
        name: 'Name',
        formatter: (
          name: Row[1],
          { cells: [{ data: id }] }: FormatterRow<Row>
        ) => wrap(<NameCell id={id} name={name} />),
      },
      'Age',
    ],
    data: props.rows,
    sort: true,
    search: true,
  });

  onMount(() => {
    grid.render(gridRef);
  });

  return <div ref={gridRef} />;
};

const App: Component = () => {
  const rows: Row[] = [
    [1, 'Andrew', 14],
    [2, 'Mike', 45],
    [3, 'Elsa', 28],
  ];

  return <Table rows={rows} />;
};

export default App;

解决方案

错误的核心是SolidJS的计算没有被挂载到可销毁的根节点上。Grid.js的自定义Formatter会动态创建、销毁DOM元素,直接用render会导致Solid的根无法被清理,因此需要用createRoot手动管理根的生命周期,同时在Grid.js元素被移除时销毁这个根。

修改后的关键代码

  1. 重构Wrapper组件,添加根生命周期管理:
import { onCleanup, createRoot } from 'solid-js';

const Wrapper: Component<{ element: JSXElement; parent?: string }> = (rawProps) => {
  const props = mergeProps({ parent: 'div' }, rawProps);
  const ref = createRef<HTMLElement>();
  let dispose: (() => void) | undefined;

  onMount(() => {
    // 创建Solid根并保存销毁函数
    dispose = createRoot((dispose) => {
      render(() => props.element, ref.current!);
      return dispose;
    });
  });

  // 组件卸载时销毁Solid根,清理资源
  onCleanup(() => {
    dispose?.();
  });

  return h(props.parent, { ref });
};
  1. 其余代码保持不变即可,Grid.js的formatter返回的虚拟节点结构已经和Wrapper适配。

原理说明

  • createRoot会创建独立的Solid渲染根,返回的dispose函数可以手动销毁该根下的所有计算和组件实例。
  • onCleanup在Wrapper组件被卸载时触发,调用dispose就能彻底清理Solid相关资源,避免内存泄漏和错误提示。
  • 相比直接使用render,createRoot让我们能完全控制根的生命周期,完美适配Grid.js动态操作DOM的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 07:29:55