Sunday面试指南

Vue 3 的 shallowRef 和 markRaw 有什么区别?什么时候不需要深度响应式?

下面是一段教学用的模拟面试。

🧑‍💻 面试官:shallowRef 和 markRaw 都能避免深度响应式,它们一样吗?

🙋‍♂️ 我:shallowRef 只追踪 value 的替换,markRaw 让对象不被代理。

🧑‍💻 面试官:shallowRef 里改 count,页面为什么不更新?

🙋‍♂️ 我:内部对象没有自动转换成深层响应式对象。

🧑‍💻 面试官:那把 markRaw 对象的 nested 单独放进 reactive,nested 还一定保持原引用吗?

shallowRef 管「容器如何追踪」,markRaw 管「对象是否转换」。不要把两者都理解成深度冻结。

面试速答(60 秒版)

shallowRef 创建一个只追踪 value 访问和替换的 ref。放进去的普通对象不会自动做深层响应式转换,所以替换整个 value 可以触发更新,直接修改内部普通字段通常不会。

markRaw 则给对象标记,让它本身跳过 Vue 的代理转换。它适合某些第三方实例或不需要响应式处理的对象。

两者可以配合:用 shallowRef 保存图表实例,再在需要时替换实例。但 markRaw 不会冻结对象,也不会递归把所有嵌套对象都标记为原始。

实际选择时,我会明确数据是否采用整体替换。如果业务依赖细粒度字段更新,就不能为了性能直接改成浅层;如果使用原始对象和代理混合,还要注意引用身份差异。

浅层容器,与原始对象分开

图:内部修改不自动触发,指的是放入 shallowRef 的普通对象;已有响应式对象的行为仍然保留。

知识点详解:减少深层转换以后,谁负责触发更新?

shallowRef 的边界在 value 这一层

假设页面保存一份很大的不可变数据快照。每次刷新都得到完整新对象,而不是逐项修改旧对象。

这个场景可以评估 shallowRef:它保留内部值,不自动把整棵普通对象转换为深层代理;当 value 被替换,依赖它的更新仍然可以触发。

TypeScript

import { shallowRef } from "vue";
const state = shallowRef({ count: 0 });

state.value.count = 1; // 不会单独触发浅层 ref 的更新
state.value = { count: 2 }; // 替换 value 会触发

示例使用 Vue 官方响应式 API,Python 没有同一套框架实现。如果传入的值本来就是响应式对象,它自身的响应式行为仍然存在;“浅层”不意味着自动取消已有代理。

内部修改以后,需要更新怎么办?

可以采用整体替换,让更新规则保持一致。如果确实已经修改内部普通数据,也可以在合适位置使用 triggerRef 显式触发相关依赖。

但是,频繁修改细小字段又不断手动 triggerRef,可能说明浅层方案不符合业务。选择 shallowRef 的前提,是团队能够遵守它的更新约定,而不是只为了省转换成本。

markRaw 保护的是对象本身,不是整棵引用图

假设图表库返回一个复杂实例。我们不希望 Vue 给它套代理,可以使用 markRaw,让这个实例保持原始。

但如果实例内部有 nested,nested 本身没有单独标记。把它拿出来放进另一个 reactive 对象,再读取时,就可能得到代理后的引用。

于是,原始 nested 与代理 nested 用 === 比较可能不同。集合键、第三方实例判断等依赖身份的场景,需要特别注意。

这些浅层和身份边界可以核对 Vue 高级响应式 API。

原始 nested 与代理 nested 可能不同

图:原始 nested 与代理 nested 可能不同。

什么时候用,什么时候不要用?

数据特征可以评估
大数据快照,每次整体替换shallowRef
不希望代理的第三方实例markRaw
需要同时替换第三方实例shallowRef 配合 markRaw
经常依赖嵌套字段变化常规深层响应式或明确局部设计

它们都不是 readonly,也不是 Object.freeze。对象仍然可能被其他代码修改,只是响应式追踪范围改变了。

此外,保存图表实例还要处理卸载时的 dispose。跳过代理并不会自动释放第三方资源,这属于实例生命周期,而不是响应式 API 的职责。

面试官继续追问

shallowRef.value 赋回同一个对象,会触发吗?

不能依靠这种写法表达内部变更。同一引用没有产生预期的值替换;需要按框架规则使用新对象或显式触发。

markRaw 可以提升所有页面性能吗?

不能。失去需要的追踪会导致界面不更新。只有确认转换成本和数据使用方式后,才值得使用。

大列表一定改成 shallowRef 吗?

先确认瓶颈是转换、渲染还是布局。浅层只解决其中一部分,虚拟列表和组件组织可能更重要。

面试速记卡

  • shallowRef:追踪 value 的访问与替换。
  • 内部普通字段:修改不会自动触发浅层 ref。
  • markRaw:对象本身跳过代理,不递归冻结。
  • 身份风险:原始对象与代理引用可能不同。
  • 工程前提:明确整体替换约定和资源清理。

公司面试真题

这道题暂未收录可核验的公司真题来源。你可以先阅读本文解析,或浏览已收录的公司面试真题。

浏览公司面试真题 →
简历汪永久免费在线制作简历,模板直接套用、导出无水印,永久免费、下载免费,不需要付费解锁任何功能。去写简历