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

React集成DataTable更新时触发removeChild错误,求解决方案

React中DataTable更新时出现removeChild错误的解决方案

问题描述

在React项目中使用DataTable,每次执行更新操作时都会抛出错误:Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node,且必须使用该DataTable。原代码如下:

const columns = [
  { title: "Category", data: "category" },
  { title: "Name", data: "name" },
  { title: "Subscribers", data: "subscribers" },
  { title: "Total News Received", data: "total_news_received" },
];

const Table = ({ selectionRange }) => {
  const tableRef = useRef();
  const dispatch = useDispatch();

  const {
    loading_no_subscribers,
    data,
    news_stats_error,
  } = useSelector((state) => state.GetNoSubscribersReducer);

  useEffect(() => {
    dispatch(GetNoSubscribersAction({ selectionRange }));
  }, [dispatch, selectionRange]);

  useEffect(() => {
    if (data && data.result) {
      const tableData = [
        ...Object.entries(data?.result?.total_subscribers_service_providers_count).map(([key, value]) => ({
          category: "Service Providers",
          name: key.replace('_', ' '),
          subscribers: value,
          total_news_received: data?.result?.total_news_recieved_service_providers[key] || 0,
        })),
        ...Object.entries(data?.ind).map(([key, value]) => ({
          category: "Industry",
          name: key
          subscribers: value,
          total_news_received: data?.ind[key] || 0,
        })),
        ...Object.entries(data?.tt).map(([key, value]) => ({
          category: "Avasant Subscribers",
          name: key.replace(/^\d+_/, '').replace('_', ' '),
          subscribers: value,
          total_news_received: data?.tt[key] || 0,
        })),
      ];

      if ($.fn.DataTable.isDataTable(tableRef.current)) {
      
        $(tableRef.current).DataTable().clear().destroy();
        $(tableRef.current).find('tbody').empty();  // Clear the table body
      }

    
      $(tableRef.current).DataTable({
        
        data: tableData,
        columns: columns,
      });
      
    }
  }, [data]);

  return (
    <section>
      <h2 style={{ color: '#136ebd' }}>Subscribers Statistics</h2>
      {loading_no_subscribers ? (
        <Loader />
      ) : news_stats_error ? (
        <p className="text-sm text-red-800">Something went wrong: {news_stats_error}</p>
      ) : (
        <table
          ref={tableRef}
          className="display min-w-full divide-y divide-gray-200 dark:divide-neutral-700 border border-gray-100 dark:border-neutral-300"
          style={{ borderRadius: '7px' }}
        >
          <thead>
            <tr style={{ backgroundColor: '#136ebd' }}>
              <th className="px-6 py-3 text-start text-xs font-medium text-gray-100 uppercase dark:text-neutral-500">Category</th>
              <th className="px-6 py-3 text-start text-xs font-medium text-gray-100 uppercase dark:text-neutral-500">Sub Category</th>
              <th className="px-6 py-3 text-start text-xs font-medium text-gray-100 uppercase dark:text-neutral-500">Subscribers</th>
              <th className="px-6 py-3 text-start text-xs font-medium text-gray-100 uppercase dark:text-neutral-500">Total News Received</th>
            </tr>
          </thead>
          <tbody>
            {/* DataTables will populate rows here */}
          </tbody>
        </table>
      )}
    </section>
  );
};

export default Table;

原因分析

  1. 语法错误:处理data?.ind的map函数中,name: key后缺少逗号,导致数据生成失败,间接引发DOM操作异常。
  2. 虚拟DOM与原生DOM冲突:手动渲染的<thead>会和DataTables自动生成的表头重复,当DataTables更新DOM时,React虚拟DOM管理与原生DOM操作出现不一致,导致移除节点时找不到对应子节点。
  3. 实例销毁不彻底:重新初始化前手动清空tbody的操作干扰了DataTables的内部DOM管理,且未在组件卸载时清理实例,引发内存泄漏和DOM残留。

解决方案

  1. 修复语法错误,确保数据正确生成;
  2. 移除手动渲染的thead,让DataTables自动生成表头,避免DOM结构冲突;
  3. 在useEffect的清理函数中销毁DataTable实例,优化实例生命周期管理。

修复后的完整代码

const columns = [
  { title: "Category", data: "category" },
  { title: "Name", data: "name" },
  { title: "Subscribers", data: "subscribers" },
  { title: "Total News Received", data: "total_news_received" },
];

const Table = ({ selectionRange }) => {
  const tableRef = useRef();
  const dispatch = useDispatch();

  const {
    loading_no_subscribers,
    data,
    news_stats_error,
  } = useSelector((state) => state.GetNoSubscribersReducer);

  useEffect(() => {
    dispatch(GetNoSubscribersAction({ selectionRange }));
  }, [dispatch, selectionRange]);

  useEffect(() => {
    let tableInstance = null;

    if (data && data.result) {
      // 修复语法错误:补全逗号
      const tableData = [
        ...Object.entries(data?.result?.total_subscribers_service_providers_count).map(([key, value]) => ({
          category: "Service Providers",
          name: key.replace('_', ' '),
          subscribers: value,
          total_news_received: data?.result?.total_news_recieved_service_providers[key] || 0,
        })),
        ...Object.entries(data?.ind).map(([key, value]) => ({
          category: "Industry",
          name: key, // 补全缺失的逗号
          subscribers: value,
          total_news_received: data?.ind[key] || 0,
        })),
        ...Object.entries(data?.tt).map(([key, value]) => ({
          category: "Avasant Subscribers",
          name: key.replace(/^\d+_/, '').replace('_', ' '),
          subscribers: value,
          total_news_received: data?.tt[key] || 0,
        })),
      ];

      // 销毁旧实例
      if ($.fn.DataTable.isDataTable(tableRef.current)) {
        $(tableRef.current).DataTable().destroy();
      }

      // 初始化新实例,配置表头样式
      tableInstance = $(tableRef.current).DataTable({
        data: tableData,
        columns: columns,
        initComplete: function() {
          // 手动设置表头样式,替代之前的手动thead
          $(this.api().table().header()).css({
            backgroundColor: '#136ebd'
          });
          $(this.api().table().header()).find('th').addClass('px-6 py-3 text-start text-xs font-medium text-gray-100 uppercase dark:text-neutral-500');
        }
      });
    }

    // 组件卸载或data更新前销毁实例
    return () => {
      if (tableInstance) {
        tableInstance.destroy();
      }
    };
  }, [data]);

  return (
    <section>
      <h2 style={{ color: '#136ebd' }}>Subscribers Statistics</h2>
      {loading_no_subscribers ? (
        <Loader />
      ) : news_stats_error ? (
        <p className="text-sm text-red-800">Something went wrong: {news_stats_error}</p>
      ) : (
        // 移除手动渲染的thead,由DataTables自动生成
        <table
          ref={tableRef}
          className="display min-w-full divide-y divide-gray-200 dark:divide-neutral-700 border border-gray-100 dark:border-neutral-300"
          style={{ borderRadius: '7px' }}
        >
          <tbody></tbody>
        </table>
      )}
    </section>
  );
};

export default Table;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 17:35:53