使用Value Getters触发Max call stack exceeded的解决方法咨询
解决AG Grid依赖链过长导致栈溢出的技巧
针对你遇到的Value Getter递归调用栈溢出问题,核心原因是在Value Getter中使用api.getValue会触发依赖行的Value Getter,若依赖链过长或存在隐式循环,就会超出JS调用栈限制。以下是几种实用的解决方法:
1. 预计算汇总行数据(推荐)
放弃在Value Getter中实时计算,改为在数据初始化、原始数据更新时提前计算所有汇总行的结果,直接存入数据对象中。这样Value Getter只需简单返回预计算的值,完全避免递归调用。
实现步骤:
- 定义汇总行配置,明确每个汇总行的ID和依赖的行ID列表
- 编写计算函数,遍历所有汇总行,基于原始数据求和并赋值
- 在数据加载或变更时调用计算函数,再将处理后的数据传给AG Grid
代码示例:
// 汇总行配置:key为汇总行rowkey,value为依赖的行ID列表 const summaryConfigs = new Map([ ["6", rowkey6Rows], ["8", rowkey8Rows], ["22", rowkey22Rows], ["36", rowkey36Rows], // 其他20个汇总行配置 ]); // 数值列字段列表(你的16个数值列) const numericColumns = ["col1", "col2", ...]; // 预计算汇总行的函数 function computeSummaryRows(rowData) { // 把行数据按rowkey映射,快速查找 const rowMap = new Map(rowData.map(row => [row.rowkey, row])); summaryConfigs.forEach((dependKeys, summaryKey) => { const summaryRow = rowMap.get(summaryKey); if (!summaryRow) return; // 对每个数值列计算求和 numericColumns.forEach(col => { let total = 0; dependKeys.forEach(key => { const dependRow = rowMap.get(key); if (dependRow) { const num = parseFloat(dependRow[col] || "0"); if (!isNaN(num)) total += num; } }); // 将计算结果存入汇总行对应列(保持字符串格式) summaryRow[col] = total.toString(); }); }); return rowData; } // 使用方式:加载原始数据后先计算,再传给AG Grid const rawRowData = [...]; // 你的原始数据 const processedRowData = computeSummaryRows(rawRowData); // 把processedRowData设置为AG Grid的rowData
此时Value Getter可以简化为:
const calculatedRowsValueGetter = (params) => { return params.data[params.colDef.field]; };
2. 直接访问原始数据数组,避免调用api.getValue
如果必须在Value Getter中计算,不要使用params.api.getValue(会触发依赖行的Value Getter),而是直接从原始数据数组中查找依赖行的原始值,手动求和。
代码示例:
// 假设你的原始数据数组是全局或可访问的rowData const rowData = [...]; const rowMap = new Map(rowData.map(row => [row.rowkey, row])); const calculatedRowsValueGetter = (params) => { const currentRowKey = params.data.rowkey; let dependKeys = []; // 获取当前汇总行依赖的行ID列表 switch(currentRowKey) { case "6": dependKeys = rowkey6Rows; break; case "8": dependKeys = rowkey8Rows; break; case "22": dependKeys = rowkey22Rows; break; case "36": dependKeys = rowkey36Rows; break; // 其他case... default: return params.data[params.colDef.field]; } // 直接从rowMap取原始值求和 const values = dependKeys.map(key => { const row = rowMap.get(key); return row ? row[params.colDef.field] : "0"; }); return trySumStringArray(values); };
这种方式不会触发依赖行的Value Getter,切断了递归调用链,避免栈溢出。
3. 使用Cell Expressions引用其他行(可选)
如果想用Cell Expressions替代Value Getter,可以通过ctx.rowData访问所有行数据,直接查找依赖行的原始值。
示例表达式(针对某一列的汇总行):
假设要给rowkey为"6"的行的col1列设置表达式:
// 表达式内容 ctx.rowData.filter(r => ["1","2","3"].includes(r.rowkey)) // 依赖的行ID列表 .reduce((sum, r) => sum + parseFloat(r.col1 || "0"), 0) .toString()
你可以为每个汇总行的每个数值列单独设置Cell Expression,或者通过列定义的cellClassRules配合动态表达式实现。注意要避免循环依赖,且表达式直接访问原始数据,不会触发其他行的Value Getter。
4. 排查循环依赖
先检查你的汇总行依赖链,是否存在循环(比如行A依赖行B,行B又依赖行A),这是导致栈溢出的常见隐性原因,必须先排除这种情况。
内容的提问来源于stack exchange,提问作者Matt1987
相关产品推荐
相关产品推荐

