跳转至

title: [ISSUE-0013] 列宽 fix 的 useMemo 形同虚设(v0.10.19 修复不彻底) description: "v0.10.19 列宽 fix 没修到根 — useMemo deps 含不稳定数组引用" tags: [issue] created: 2026-05-26 updated: 2026-05-26 type: issue status: fixed severity: critical


[ISSUE-0013] 列宽 fix 的 useMemo 形同虚设(v0.10.19 修复不彻底)

相关源码src/components/table/client-data-table.tsxsrc/sections/page/local-data-table.tsx 发现途径:v0.10.19 代码审查(agent)

用户感知的现象

ISSUE-0010 v0.10.19 fix 没真正解决:拖列宽后仍被重置。

根因分析

v0.10.19 加的 useMemo:

const memoColumns = useMemo(() => { ... }, [columnsList, columnsWidth, defaultColumns]);

defaultColumns 是调用方每次 render 新建的数组:

// local-data-table.tsx
const columns = [...];  // 每次 render 新数组
<ClientDataTable defaultColumns={columns} ... />

Object.is(prev, next) 永远 false → useMemo 每次都重算 → 新数组引用 → DataGridPremium 看到 columns prop 变化 → 内部 width state 重置。

等于没修

修复方案

把 deps 用「按 field 列表的字符串签名」做稳定 key:

const memoColumns = useMemo(() => { ... }, [
  columnsList,
  columnsWidth,
  defaultColumns.map((c) => c.field).join(','), // 内容变才触发
]);

字符串签名仅在 columns 集合变化时变(field 增/减/换序),引用稳定 → DataGridPremium 不会被 false-positive 触发重置。

改动文件

文件 改了什么
src/components/table/client-data-table.tsx useMemo deps 改用 defaultColumns.map(c=>c.field).join(',') 字符串签名

验证方式

  1. 进入数据列表,拖动「商家」列宽到很宽
  2. 任何 state 变化(切 chip / 翻页 / 切换任务筛选 / 关 drawer)
  3. 列宽应保持
  4. F5 刷新页面后列宽仍保持(localStorage 持久化)
  5. 多次连续拖动多列,所有列宽都正确保留

如何避免再犯

  • useMemo deps 含 object/array 必须警惕:调用方传 prop 每次 render 新建就是定时炸弹
  • 「修了 bug」≠「修到根」:写 fix 后必须真的复现一遍。当时我没回到浏览器拖一次列宽测,所以漏检
  • memo deps 用字符串签名是个稳定模式arr.map(...).join(',') 比 deep-equal 库便宜,已知场景下够用
  • 不可信「调用方一定 useMemo」:你的组件应该独立稳定,不能假设调用方传稳定引用

相关问题

  • ISSUE-0010 — 同一问题的第一次「修复」