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 导致的性能崩溃或报错。