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.tsx、src/sections/page/local-data-table.tsx发现途径:v0.10.19 代码审查(agent)
用户感知的现象¶
ISSUE-0010 v0.10.19 fix 没真正解决:拖列宽后仍被重置。
根因分析¶
v0.10.19 加的 useMemo:
但 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(',') 字符串签名 |
验证方式¶
- 进入数据列表,拖动「商家」列宽到很宽
- 任何 state 变化(切 chip / 翻页 / 切换任务筛选 / 关 drawer)
- 列宽应保持
- F5 刷新页面后列宽仍保持(localStorage 持久化)
- 多次连续拖动多列,所有列宽都正确保留
如何避免再犯¶
- useMemo deps 含 object/array 必须警惕:调用方传 prop 每次 render 新建就是定时炸弹
- 「修了 bug」≠「修到根」:写 fix 后必须真的复现一遍。当时我没回到浏览器拖一次列宽测,所以漏检
- memo deps 用字符串签名是个稳定模式:
arr.map(...).join(',')比 deep-equal 库便宜,已知场景下够用 - 不可信「调用方一定 useMemo」:你的组件应该独立稳定,不能假设调用方传稳定引用
相关问题¶
- ISSUE-0010 — 同一问题的第一次「修复」