[深入vue3之响应性API] reactive、readonly、shallowReactive、shallowReadonly、toRaw、markRaw等使用与讲解
作者:互联网
reactive
- 返回对象的响应式副本
- 响应式转换是“深层”的——它影响所有嵌套 property。在基于 ES2015 Proxy 的实现中,返回的 proxy 是不等于原始对象的。建议只使用响应式 proxy,避免依赖原始对象。
- 只能传入引用类型,否则抛出警告。 reactive 将解包所有深层的 refs,同时维持 ref 的响应性。正确的讲应该是:当它通过代理访问时,会被自动解包:
<script lang='ts' setup>
import { ref,reactive } from 'vue';
let rea1 = reactive({ count: 0 }) // Proxy
let refData = ref('1') // RedfImpl 构造函数的对象
//! ***reactive 将解包所有深层的 refs,同时维持 ref 的响应性。***
//! ***正确的讲应该是:当它通过代理访问时,会被自动解包:***
let rea2 = reactive<any>({refData})
//! 当将 ref 分配给 reactive property 时,效果同上
rea2.re2_1 = refData // console.log(rea2.re2_1) > 打印 '1'
// 因为访问 reactive 内的 ref 会自动解包,所以不需要 .value
rea2.refData = '测试'
// 任何类型的新属性都是 proxy 类型
rea2.newObj = {data1:'同样是响应式的'}
</script>
readonly
- 接受一个对象 (响应式或纯对象) 或 ref 并返回原始对象的只读代理。只读代理是深层的:任何被访问的嵌套 property 也是只读的。
- 与 reactive 一样,如果任何 property 使用了 ref,当它通过代理访问时,则被自动解包:
<script lang='ts' setup>
import { ref,readonly } from 'vue';
let refData = ref('1') // RedfImpl 构造函数的对象
const read1 = readonly({a:1})
console.log(read1); // read1.count = 123 会报错
const read2 = readonly({refData}) // console.log(read2.refData); // 1
</script>
shallowReactive
- 创建一个响应式代理,它跟踪其自身 property 的响应性,但不执行嵌套对象的深层响应式转换 (暴露原始值)。
<script lang='ts' setup>
import { shallowReactive } from 'vue';
const state = shallowReactive({
foo: 1,
nested: {
bar: 2
}
})
// 改变 state 本身的性质是响应式的
state.foo++
// ...但是不转换嵌套对象
isReactive(state.nested) // false
state.nested.bar++ // 非响应式
</script>
与 reactive 不同,任何使用 ref 的 property 都不会被代理自动解包。因为ref生成的是个对象!
例如 a = shallowReactive({ b:ref('1') })
为 a.b.value,本质是嵌套的。
shallowReadonly
- 跟上面的一样,浅只读转换,嵌套的对象可以进行操作
const state = shallowReadonly({
foo: 1,
nested: {
bar: 2
}
})
// 改变 state 本身的 property 将失败
state.foo++
// ...但适用于嵌套对象
isReadonly(state.nested) // false
state.nested.bar++ // 适用
与 readonly 不同,任何使用 ref 的 property 都不会被代理自动解包。因为ref生成的是个对象!
例如 a = shallowReadonly({ b:ref('1') }) 为 a.b.value,本质是嵌套的。
toRaw
- 返回 reactive 或 readonly 代理的原始对象。
- 这是一个“逃生舱”,可用于临时读取数据而无需承担代理访问/跟踪的开销,也可用于写入数据而避免触发更改。不建议保留对原始对象的持久引用。请谨慎使用。
<script lang='ts' setup>
import { toRaw } from 'vue';
const foo = {a:111}
const reactiveFoo = reactive(foo)
console.log(toRaw(reactiveFoo) === foo,reactiveFoo===foo) // true , 代理的则为false
</script>
markRaw
- 标记一个对象,使其永远不会转换为 proxy。返回对象本身。
- markRaw 只作用于根级别,因此内部的子级对象会被转为响应式
. - markRaw 总结: (按照重点从上到下)
- <原则>:1、markRaw 标记一个对象,使其永远不会转换为 proxy。
- <原则>:2、返回对象本身。
- 3、markRaw 只作用于根级别,因此内部的子级对象会被转为响应式
- 4、markRaw() 虽然会使普通对象永远不会转换为 proxy ,但是如果传入的本身就是proxy ,那返回的也是proxy。
<script lang='ts' setup>
import { markRaw } from 'vue';
// markRaw 标记一个对象,使其永远不会转换为 proxy。返回对象本身。嵌套多深都不会转 proxy
// const foo = markRaw({})
// console.log(isReactive(reactive(foo))) // false
// // const bar = reactive({ foo }) // console.log(isReactive(bar.foo)) // false
const foo = markRaw({
nested: {}
})
// markRaw 只作用于根级别,因此内部的子级对象会被转为响应式
// bar.nested是响应式的
const bar = reactive({
// 虽然 `foo` 被标记为原始,但 foo.nested 不是。
nested: foo.nested
})
let asx:any = reactive({a:123})
let as1 = markRaw({}) // 普通对象
let as2 = markRaw(asx) // 原始 asx; as2 === asx > true
</script>
其他更多vue3 选项式api、组合式api、全局/应用api学习经验分享
vue3 学习资料vue3学习资料记录,经验交流、分享https://oumae-kumiko.github.io/vue3.cn.community/
标签:shallowReadonly,对象,shallowReactive,nested,reactive,markRaw,foo,ref 来源: https://blog.csdn.net/lijiahui_/article/details/122539570