Vue Reactivity API 全解

1. ref vs reactive

(1) ref (任意类型)

  • 目标: 基础类型 (0) 或对象 ({})。
  • 原理: 通过 .value 的 get/set 拦截。如果值是对象,内部自动调用 reactive
  • 建议: 推荐全使用 ref,减少心智负担。

(2) reactive (深度对象代理)

  • 目标: 只能是对象 (Object/Array/Map/Set)。
  • 原理: Proxy 深度代理。
  • 局限性:
    • 解构丢失响应式const { count } = state 出来的 count 不再响应。必须用 toRefs
    • 不能替换整个对象state = {} 会断开连接。

2. 进阶 API (性能优化)

(1) shallowRef & shallowReactive

用于性能优化,只代理第一层。

  • 场景: 大数据量(地图数据、ECharts 实例、大型不可变 JSON)。不希望 Vue 去递归代理内部成千上万个属性。
  • 配合: triggerRef(myRef) 可强制触发更新。

(2) readonly (只读代理)

  • 作用:创建一个深层只读的对象。任何修改尝试都会失败并报警。
  • 场景
    • Provide: 父组件提供数据给子组件,不希望子组件修改(单向数据流)。
    • Hook 返回:防止使用者意外修改内部状态。

(3) toRaw (获取原始对象)

  • 作用:从 Proxy 对象中取出原始对象 (Raw Object)。
  • 特点:修改 Raw 对象不会触发 UI 更新
  • 场景:性能逃逸。比如对大数组做复杂计算,不需要中间过程更新 UI。

(4) markRaw (标记非响应式)

  • 作用:标记一个对象,告诉 Vue 永远不要把它变成响应式
  • 场景:第三方库实例(如 Three.js 场景对象),防止 Proxy 导致的性能崩溃或报错。