DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
PanstarCloud:部署应用,接入 AI,云服务器与 AI 网关
OnlineSIM:在线接收短信,虚拟号码租用

Vue KeepAlive 淘汰后只停用不卸载:检查已挂载 VNode 复用

Vue 3.5.43 复用已挂载 VNode 后,max 淘汰可能只触发 deactivated,旧监听仍运行。3.5.44 修正克隆节点保活标记的清理。

KeepAlive 设置了 max="1",切换到新页面后,旧页面只触发 deactivated,却一直不触发 unmounted;它的 watcher 或导航监听仍在运行。如果父级渲染重复返回已经挂载过的 VNode,应检查缓存淘汰时是否清除了真正挂载节点上的保活标记。

Vue 3.5.43 有这条具体路径,正式 3.5.44 的发行修正已覆盖“挂载时被克隆的当前 VNode 被淘汰却未卸载”。普通缓存命中时只停用组件属于 KeepAlive 的正常行为;需要先确认它确实已因 max 限制被淘汰,不能把所有 deactivated 都视为泄漏。

缓存中的节点与 current 不再是同一份 VNode

触发顺序是父级先返回上次已挂载的保活节点,再从组件 A 切到新缓存键 B。KeepAlive 和后续标准化可能各克隆一次 VNode,实际挂载、写入缓存的节点与内部 current 不再是同一个对象。

旧淘汰逻辑判断两者属于同一组件类型和 key 后,只清理 current 的保活标记。实际挂载节点仍保留标记,接下来的替换便把 A 移入存储容器,而非执行卸载。A 又已经不在缓存中,后续既无法正常命中,也没有按预期完成销毁。

先按组件身份记录激活、停用、淘汰及卸载的顺序,并核对是否复用了已挂载 VNode。组件仍在有效缓存里、应用自己的监听没有在既有清理入口注销、或同时存在另一个 A 实例,都是需要分开判断的情况。

修复淘汰路径,而不是不断更换 key

项目兼容时,采用 Vue 3.5.44,并核对框架实际解析的 runtime-core。框架管理的 Vue 内部依赖应成套更新,不能只在根清单声明一个版本,或把不同版本的内部包强行拼接。

自己编写渲染封装时,也应检查是否不必要地长期返回同一个已经挂载的 VNode。需要复用的是组件状态还是节点对象,应按封装契约区分;不能随意重写框架内部页面节点来规避问题。

暂时无法更新且该页面可以失去保活状态时,可通过原有页面缓存配置停用受影响页面的保活。重新挂载会改变表单、滚动位置与数据加载,应先确认业务允许。把 max 调大或每次生成随机 key 可能改变出现频率,却不能证明淘汰后的实例已销毁。

验收使用原来的已挂载节点复用顺序,让 A 因容量限制被 B 淘汰,确认 A 的卸载及清理执行,后续 watcher 和导航监听不再以旧实例身份工作。另验仍在缓存里的正常页面能保留状态;仅看到控制台不报错,无法判断持续运行的旧实例是否已经退出。