在 Vue 3 的响应式系统中,shallowReactive
、shallowReadonly
、toRaw
和 markRaw
是用于精细化控制响应性和数据行为的高级 API。它们适用于需要对响应式对象进行更细粒度管理的场景。
🧩 一、shallowReactive
✅ 作用:
创建一个 浅层响应式对象,仅对对象的第一层属性进行响应式转换,不会递归处理嵌套对象。
示例:
import { shallowReactive } from 'vue'
const state = shallowReactive({
user: {
name: 'Alice',
profile: {
age: 25
}
}
})
// 修改第一层属性是响应式的
state.user = { name: 'Bob' }
// 修改嵌套属性不是响应式的 ❌
state.user.profile.age++
⚠️ 此时
profile.age
的变化不会触发视图更新。
🔒 二、shallowReadonly
✅ 作用:
创建一个 浅只读对象,其自身属性不可更改,但嵌套对象不会被深度冻结。
示例:
import { shallowReadonly } from 'vue'
const config = shallowReadonly({
theme: 'dark',
settings: {
fontSize: 14,
layout: 'sidebar'
}
})
config.theme = 'light' // ❌ 报错:不能修改只读属性
config.settings.fontSize = 16 // ✅ 成功:settings 是普通对象,未被深度冻结
📦 三、toRaw
✅ 作用:
获取一个响应式或只读对象的原始对象(即去除响应式包装)。
使用场景:
- 当你需要将响应式对象传给第三方库时(如 JSON.stringify、axios 请求等)
- 避免 Vue 对对象进行不必要的追踪
示例:
import { reactive, toRaw } from 'vue'
const state = reactive({ count: 0 })
const rawState = toRaw(state)
console.log(rawState === state) // false
console.log(rawState.count) // 0
⚠️
toRaw
可以穿透reactive
、readonly
、shallowReactive
等包装。
🚫 四、markRaw
✅ 作用:
标记一个对象,使其永远不会被转为响应式。即使你把它传给 reactive()
或作为响应式对象的属性。
使用场景:
- 将大型对象、第三方库实例排除在响应式系统之外
- 提升性能,避免不必要的代理创建
示例:
import { markRaw, reactive } from 'vue'
class User {
constructor(name) {
this.name = name
}
}
const user = markRaw(new User('Alice'))
const state = reactive({ user })
console.log(state.user === user) // true
console.log(isReactive(state)) // true
console.log(isReactive(state.user)) // false
✅
user
被标记为 raw,即使放入响应式对象中也不会被代理。
📊 对比总结表
API | 响应式层级 | 是否可写 | 是否解包嵌套对象 | 典型用途 |
---|---|---|---|---|
reactive() | 深层响应式 | ✅ 可写 | ✅ 自动解包 | 默认首选 |
shallowReactive() | 浅层响应式 | ✅ 可写 | ❌ 不解包 | 性能优化 |
readonly() | 深层只读 | ❌ 不可写 | ✅ 自动解包 | 数据保护 |
shallowReadonly() | 浅层只读 | ❌ 不可写 | ❌ 不解包 | 控制只读范围 |
toRaw() | 获取原始对象 | - | - | 获取非响应式副本 |
markRaw() | 排除响应式 | - | - | 第三方对象、性能优化 |
💡 最佳实践建议
场景 | 推荐使用 |
---|---|
默认状态管理 | reactive() / ref() |
大型对象/频繁局部更新 | shallowReactive() + trigger() |
只想冻结顶层属性 | shallowReadonly() |
需要原始对象 | toRaw() |
排除某些对象进入响应式系统 | markRaw() |