v-memo缓存指定依赖未变时的整棵子树VNode,跳过diff与更新;适用于结构稳定但外部状态高频变化的场景,需精准声明依赖数组以避免失效或性能倒退。

Vue 3.2+ 引入的 v-memo 不是用来“缓存静态 VNode”的——它缓存的是**一组 VNode 的渲染结果(即 patch flag 对应的子树)**,且仅在依赖值未变化时跳过该子树的 diff 和更新。它不改变节点是否“静态”,也不替代 v-once 或编译器自动标记的静态提升。
理解 v-memo 的真实作用
v-memo 是一个指令,接收一个数组作为依赖项(如 v-memo="[count, isActive]")。当数组中每个值与上一次完全相等(Object.is)时,Vue 会复用上次生成的子树 VNode,跳过整个子树的 props 更新、事件重绑定、子组件重新渲染、内部 diff 等开销。
它不是内存级缓存,不持久化;也不是对单个节点生效,而是作用于其包裹的整个模板片段(即它的直接子节点构成的子树)。
什么场景下 v-memo 真正提效?
适用于:子树结构稳定、内部状态/props 高频变化但实际无需重渲染的场景。典型例子:
根据 package.json 中的 engines 字段自动检测 Node.js 版本需求,未安装 nvm 时自动安装并切换至对应版本。支持 Windows、macOS、Linux。适用于 Node.js 项目开发、版本切换和环境配置。
立即学习“前端免费学习笔记(深入)”;
- 长列表中,某一项的展示内容由外部状态控制(如全局搜索关键词),但该项自身 props(id、name)不变 → 可
v-memo="[item.id, globalSearchKey]" - 表单区域包含多个输入框,但某些只读字段(如用户角色 badge)仅随用户对象变化 →
v-memo="[user.role, user.status]"包裹 badge 区域 - 条件渲染分支中,某个分支内含大量静态结构 + 少量动态文本,且该分支的触发条件变化频繁但内容不变 → 缓存整个分支
怎么写才有效?避坑要点
无效写法比比皆是。关键原则:依赖数组必须精准反映“是否需要重渲染”的判断依据。
-
别漏掉影响渲染结果的响应式变量:比如用
v-memo="[item.id]"包裹显示{{ item.name }}的 div,但item.name会异步更新 → 缓存失效,UI 不更新 -
别放非响应式或常量:如
v-memo="[1, true]"永远命中缓存,导致更新卡死 - 别滥用在根节点或大范围区域:v-memo 本身有比对开销;若依赖数组过大或频繁变动,反而拖慢性能
-
别和 v-for 直接混用在同一个元素上:Vue 不支持。正确做法是把
v-memo放在v-for内部的每一项容器上(如<li v-for="i in list" :key="i.id"><div v-memo="[i.id, i.status]">...</div></li>)
对比 v-once 和静态提升,它解决什么?
v-once:只渲染一次,后续完全不响应更新 —— 适合真正静态内容。
编译器静态提升:自动把纯静态节点提到 setup() 外层,避免重复创建 —— 你无需写,Vue 自动做。v-memo:填补中间地带 —— 内容会变,但变的频率低 / 变的只是局部,且你明确知道哪些变量变了才需要重算。
例如:<UserCard v-memo="[user.id, user.lastLoginAt]"> 中,只要 user.id 和 user.lastLoginAt 不变,即使父组件其他响应式数据变了,卡片内部也不会执行 patch,哪怕它用了 computed 或嵌套子组件。

















