标准答案

  1. shallowRef 只追踪 .value 的替换,不会深度追踪 value 内部对象属性变化,适合大对象、外部实例或手动整体替换的状态。
  2. shallowReactive 只让对象第一层属性响应式,嵌套对象不会继续转成深层响应式。
  3. markRaw 会标记一个对象不被 Vue 转成响应式代理,适合图表实例、编辑器实例、地图实例等第三方对象。
  4. 这些 API 不是性能优化的默认选项,只有在深层响应式成本高、代理会破坏实例行为或确实只关心引用变化时才使用。
  5. 使用浅层响应式后,内部字段变更不会自动触发视图更新,需要通过整体替换、triggerRef 或其它明确方式通知更新。

题目解析

这道题的重点是响应式深度,而不是把这些 API 统一说成“性能优化”。

普通业务表单、简单对象和组件状态一般不需要 shallow 或 markRaw,默认 ref/reactive 更直观。

第三方库实例被 Proxy 包裹后可能出现身份判断、私有字段或方法绑定问题,markRaw 可以避免这类风险。

代码示例

下面展示了用 shallowRef 保存大对象引用,以及用 markRaw 保存第三方实例。

TypeScript
const chartOptions = shallowRef(createLargeOptions())

function updateOptions() {
  chartOptions.value = createLargeOptions()
}
TypeScript
const chart = shallowRef<Chart | null>(null)

onMounted(() => {
  chart.value = markRaw(new Chart(canvasRef.value))
})

常见误区

  • 把 shallowRef 当成普通 ref 使用,修改内部字段后疑惑页面为什么不更新。
  • 为了所谓性能到处使用 markRaw,导致响应式链路断开且问题难排查。
  • 不知道第三方实例可以跳过响应式代理,反而把实例塞进 deep reactive 对象里。

作者信息