Vue 列表一渲染就报 reading 'memo',检查 v-memo 配合三元 key 的编译结果
v-memo 列表使用三元 key 时,3.5.43编译条件优先级可能让首次渲染读取不存在的缓存。用函数key暂避,核对3.5.44与memo依赖。
列表还没完成首次渲染,就报 Cannot read properties of undefined (reading 'memo'),栈落在 isMemoSame。如果同一个 v-for 元素上用了 v-memo,而 :key 是三元表达式,可以检查Vue编译器是否把key表达式放进了错误的运算优先级。
这条路径在Vue 3.5.43有具体复现,已在3.5.44正式版修复。它不等于key值重复,也不是所有memo依赖都不能写对象;确认版本和生成条件后再改,避免把一般列表状态问题混在一起。
初次渲染没有缓存,却执行了缓存比较
触发模板可以简化为:
<span
v-for="item in items"
:key="item.kind === 'a' ? item.a : item.b"
v-memo="[item]"
>
{{ item.a }}
</span>
这里 items、kind、a、b 为结构示例,真实key仍须稳定且唯一。受影响编译器把key原样插入缓存判断,缺少围住整个表达式的括号。三元运算符的优先级低于逻辑与,导致后面的 isMemoSame 被并入三元分支,失去原本应有的缓存存在检查。
首次渲染时缓存本来就是undefined,错误条件却继续调用比较函数,读取 cached.memo 时抛错。因此,“第一次渲染为什么会读旧缓存”正是这条回归的识别点。服务端渲染也可能受影响,不能只盯着浏览器是否残留旧页面。
无法升级时,把key表达式放进函数
可以在setup中保留相同的key选择规则,让模板只调用函数:
function rowKey(item) {
return item.kind === 'a' ? item.a : item.b;
}
<span v-for="item in items" :key="rowKey(item)" v-memo="[item]">
{{ item.a }}
</span>
函数调用作为key表达式时,避免了这一处未经括号包裹的低优先级组合。它不解决原数据的重复key:若a与b的值在不同项之间会冲突,仍需按业务定义唯一标识,不能随意加数组下标让报错暂时消失。
另一种局部选择是暂时移除这处 v-memo,恢复普通列表更新。它会改变优化行为,应在实际列表规模下评估,不需要为排一个组件的故障关闭全应用缓存。
更新编译器后,还要查memo依赖本身
Vue 3.5.44于2026年10月13日发布,对v-for的memo缓存判断增加了key表达式括号,并加入条件key的检查。它修复的是编译条件的优先级,不能替应用决定该缓存哪些变化。
更新时核对实际构建使用的 @vue/compiler-core、@vue/compiler-sfc 与Vue版本。修复包到位后重新生成产物,不能继续部署旧编译输出。模板里手工多写一层括号,也应以最终产物为准,不能假设每个编译阶段都会保留源码的括号形态。
示例 v-memo="[item]" 只适合由item引用变化表达所需更新的用法。若项目就地修改 item.a 而item身份不变,memo仍可能跳过更新;应将实际影响显示的值纳入依赖,或不使用这处优化。这个后续规则与首屏读取undefined的编译错误不同,需要分别检查。
完成后先确认首次渲染不再进入无缓存的比较,再检查增加、删除、排序及需要更新的字段。保留stable key和完整memo依赖,不能以错误消失为由接受列表内容停在旧状态。


