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

使用MaterialReactTable虚拟表格时出现最大更新深度超限问题

问题:MaterialReactTable虚拟表格列宽计算导致无限重渲染错误

我用MaterialReactTable构建虚拟表格,尝试根据内容自动设置列宽。调用自定义的GetColumnWidth函数计算列宽后,在表格内导航时触发以下错误:

Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.

说明:GetColumnWidth内部没有调用setState,按逻辑不会引发无限重渲染,但将函数调用替换为固定数值(如20、42)后,表格可正常运行。

相关代码片段

// format : [{..}, {..}, ...]
const copyData = myInputTable;

// Return a dictionary with the form -> columnKey: columnwidth,
const getAllColumnWidth = () => {
    const widthDict = {};
    for (const key in copyData[0]){
        widthDict[key] = GetColumnWidth(copyData, key);  // Here is the issue
    }
    return widthDict;
}

// Data is the full table -> [{..}, {..}, ...]
// key is the key of the column concerned (1 in each object of data)
// The goal of the function is to get the longest string's length of the column
function GetColumnWidth(data, key){
    if (data == undefined || key == undefined) {
        return 42;
    }

    const longChar = "ABCDEFGHIJKLNOPQRSTUVXYZ";
    var i = 0;
    var maxLength = 0;
    for (const line of data){
        var len = 0;

        if (line[key] === null || line[key] === undefined) {
            continue;
        }

        for (const lettre of line[key].toString()) {
            // Here I'm just defining the different sizes depending on the character

            if (longChar.indexOf(lettre) !== -1) {
                len += 0.26;
            } 

            if (lettre === 'W') {
                len += 1;
            }

            if(lettre === 'M') {
                len += 0.85;
            }

            if (lettre === 'm') {
                len += 0.80;
            }

            if (lettre === 'w') {
                len += 0.66
            }

            if (lettre === ' ') {
                len += 0.55;
                continue;
            }

            len++;
        }

        // Save the length if it's the longest string ever seen in the column
        if (len > maxLength) {
            maxLength = len;
        }
    }

    const coeff = 10;
    return 20 + maxLength * coeff;
}

原因分析

  1. 重复计算触发重渲染循环:getAllColumnWidth和GetColumnWidth在组件渲染阶段被反复调用。每次表格导航(滚动、分页等),MaterialReactTable会重新计算列属性,而直接在列配置中调用这些函数,会导致每次渲染都生成新的宽度对象,触发组件重新渲染,进而再次调用函数,形成无限循环。
  2. 引用类型不稳定:getAllColumnWidth每次调用都会返回一个全新的widthDict对象,React会判定该属性发生变化,从而触发表格组件的更新。

解决办法

方法1:用useMemo缓存计算结果

将宽度计算结果缓存,仅当依赖的myInputTable变化时才重新计算,避免每次渲染生成新对象:

import { useMemo } from 'react';

// 缓存宽度计算结果,依赖myInputTable变化时才重新计算
const columnWidths = useMemo(() => {
  const widthDict = {};
  if (!myInputTable || myInputTable.length === 0) return widthDict;
  for (const key in myInputTable[0]){
      widthDict[key] = GetColumnWidth(myInputTable, key);
  }
  return widthDict;
}, [myInputTable]); // 依赖数组:仅myInputTable变化时重新执行

之后在列配置中直接使用columnWidths[key]即可。

方法2:用useEffect+状态存储计算结果

把列宽计算移到数据更新时执行,结果存入状态:

import { useState, useEffect } from 'react';

const [columnWidths, setColumnWidths] = useState({});

useEffect(() => {
  const widthDict = {};
  if (!myInputTable || myInputTable.length === 0) {
    setColumnWidths({});
    return;
  }
  for (const key in myInputTable[0]){
      widthDict[key] = GetColumnWidth(myInputTable, key);
  }
  setColumnWidths(widthDict);
}, [myInputTable]);

方法3:优化GetColumnWidth性能

该函数计算量随数据量增长而变大,可进一步缓存单列的计算结果,或者在数据加载完成后一次性计算所有列宽,减少重复计算开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 18:05:22