◆
Vue3 响应式 API:reactive、readonly、toRaw 详解
reactive
- 返回对象的响应式转换后的数据。响应式转换是“深层”的——它影响所有嵌套
property。 - 在基于
ES2015 Proxy的实现中,返回的proxy是不等于原始对象的。建议只使用响应式proxy,避免依赖原始对象。 - 通过使用
Proxy来实现对对象内部所有数据的劫持, 并通过Reflect操作对象内部数据tip
reactive将解包所有深层的refs,同时维持ref的响应性。 当将ref分配给reactive property时,ref将被自动解包。
如果使用 reactive 定义基础数据类型,则返回的仍是基础数据类型 :::
<template>
<div>reactiveBool 的值:{{ reactiveBool }}</div>
<div>reactiveTest.a 的值:{{ reactiveTest.a }}</div>
<div>reactiveTest.b 的值:{{ reactiveTest.b }}</div>
<div>reactiveLetTest.a 的值:{{ reactiveLetTest.a }}</div>
<div>reactiveLetTest.b 的值:{{ reactiveLetTest.b }}</div>
<div>refTest.a 的值:{{ refTest.a }}</div>
<div>refTest.b 的值:{{ refTest.b }}</div>
<div>reactiveRefTest.a 的值:{{ reactiveRefTest.a }}</div>
<div>reactiveRefTest.b 的值:{{ reactiveRefTest.b }}</div>
<div>reactiveObj.a 的值:{{ reactiveObj.a }}</div>
<div>reactiveObj.mytest 的值:{{ reactiveObj.mytest }}</div>
<div>refParam 的值:{{ refParam }}</div>
</template>
<script setup>
import { reactive, ref } from 'vue';
let reactiveBool = reactive(false);
const reactiveTest = reactive({
a: 1,
b: 2,
});
let reactiveLetTest = reactive({
a: 1,
b: 2,
});
const refTest = ref({
a: 1,
b: 2,
});
const reactiveRefTest = reactive(refTest);
const refParam = ref('mytest');
const reactiveObj = reactive({ a: 1 });
reactiveObj.mytest = refParam;
setTimeout(() => {
reactiveBool = true;
reactiveTest.a = 'reactive 更新了 a 的值';
reactiveLetTest.a = 'reactiveLetTest 更新了 a 的值';
refTest.a = 'refTest 更新了 a 的值';
reactiveRefTest.a = 'reactiveRefTest 更新了 a 的值';
refParam.value = '使用 ref 去改变 refParam 的值';
}, 1500);
setTimeout(() => {
// 会导致下方的失效 这样重新赋值后会,reactiveLetTest 会变成普通对象 失去响应式的效果
// reactiveLetTest = {
// a: 'reactiveLetTest 更新了 a 的值',
// b: 'reactiveLetTest 更新了 b 的值'
// }
// 这个效果和上面的效果一致
// reactiveLetTest = reactive({
// a: 'reactiveLetTest 更新了 a 的值',
// b: 'reactiveLetTest 更新了 b 的值'
// })
reactiveObj.mytest = '使用 reactiveObj 去改变 refParam 的值';
}, 3000);
setTimeout(() => {
reactiveLetTest.b = 'reactiveLetTest 更新了 b 的值';
}, 5000);
</script>
readonly
接受一个对象 (响应式或纯对象) 或 ref 并返回原始对象的只读代理。只读代理是深层的:任何被访问的嵌套 property 也是只读的。
tip
下面的示例 readonlyVars,readonlyRefs、readonlyReactives 这三个值是无法改变的
<template>
<div>normalVar 的值:{{ normalVar }}</div>
<div>normalRef 的值:{{ normalRef }}</div>
<div>normalReactive.a 的值:{{ normalReactive.a }}</div>
<div>normalReactive.b.c 的值:{{ normalReactive.b.c }}</div>
<hr />
<div>readonlyVar 的值:{{ readonlyVar }}</div>
<div>readonlyRef 的值:{{ readonlyRef }}</div>
<div>readonlyReactive.a 的值:{{ readonlyReactive.a }}</div>
<div>readonlyReactive.b.c 的值:{{ readonlyReactive.b.c }}</div>
<hr />
<div>readonlyVars 的值:{{ readonlyVars }}</div>
<div>readonlyRefs 的值:{{ readonlyRefs }}</div>
<div>readonlyReactives.a 的值:{{ readonlyReactives.a }}</div>
<div>readonlyReactives.b.c 的值:{{ readonlyReactives.b.c }}</div>
</template>
<script setup>
import { reactive, readonly, ref } from 'vue';
let normalVar = 'readonlyVar';
let normalRef = ref('readonlyRef');
let normalReactive = reactive({
a: 'readonlyReactive a',
b: {
c: 'readonlyReactive c',
},
});
let readonlyVar = 'readonlyVar';
let readonlyRef = ref('readonlyRef');
let readonlyReactive = reactive({
a: 'readonlyReactive a',
b: {
c: 'readonlyReactive c',
},
});
let readonlyVars = readonly(readonlyVar);
let readonlyRefs = readonly(readonlyRef);
let readonlyReactives = readonly(readonlyReactive);
setTimeout(() => {
normalVar = '更改 normalVar 的值';
normalRef.value = '更改 normalRef 的值';
normalReactive.a = '更改 normalReactive.a 的值';
normalReactive.b.c = '更改 normalReactive.b.c 的值';
readonlyVar = '更改 readonlyVar 的值';
readonlyRef.value = '更改 readonlyRef 的值';
readonlyReactive.a = '更改 readonlyReactive.a 的值';
readonlyReactive.b.c = '更改 readonlyReactive.b.c 的值';
}, 1500);
setTimeout(() => {
readonlyVars = '1更改 readonlyVar 的值';
readonlyRefs.value = '1更改 readonlyRef 的值';
readonlyReactives.a = '1更改 readonlyReactive.a 的值';
readonlyReactives.b.c = '1更改 readonlyReactive.b.c 的值';
}, 2000);
</script>
isProxy
检查对象是否是由 reactive 或 readonly 创建的 proxy。
<script setup>
import { isProxy, reactive, readonly, ref } from 'vue';
const normal = ref(1);
const proxyTest = new Proxy(
{
name: '小红',
age: 15,
},
{},
);
const refTest = ref(1);
const reactiveTest = reactive({
a: 1,
});
const readonlyTest = readonly(reactive({ a: 1, b: { c: 3 } }));
// false
console.log('normal', isProxy(normal));
// false
console.log('normalProxy', isProxy(proxyTest));
// false
console.log('refTest', isProxy(refTest));
// true
console.log('reactiveTest', isProxy(reactiveTest));
// true
console.log('readonlyTest', isProxy(readonlyTest));
</script>
isReactive
检查对象是否是由 reactive 创建的响应式代理。 如果该代理是 readonly 创建的,但包裹了由 reactive 创建的另一个代理,它也会返回 true。
<script setup>
import { isProxy, isReactive, reactive, readonly, ref } from 'vue';
const normal = ref(1);
const refTest = ref(1);
const reactiveTest = reactive({
a: 1,
});
const readonlyTest = readonly(reactive({ a: 1, b: { c: 3 } }));
// false
console.log('normal', isReactive(normal));
// false
console.log('refTest', isReactive(refTest));
// true
console.log('reactiveTest', isReactive(reactiveTest));
// true
console.log('readonlyTest', isReactive(readonlyTest));
</script>
isReadOnly
检查对象是否是由 readonly 创建的只读代理。
<script setup>
import { isProxy, isReadonly, reactive, readonly, ref } from 'vue';
const normal = ref(1);
const refTest = ref(1);
const reactiveTest = reactive({
a: 1,
});
const readonlyTest = readonly(reactive({ a: 1, b: { c: 3 } }));
// false
console.log('normal', isReadonly(normal));
// false
console.log('refTest', isReadonly(refTest));
// false
console.log('reactiveTest', isReadonly(reactiveTest));
// true
console.log('readonlyTest', isReadonly(readonlyTest));
</script>
toRaw
返回 reactive 或 readonly 代理的原始对象。可用于临时读取数据而无需承担代理访问/跟踪的开销,也可用于写入数据而避免触发更改。
<template>
<p>{{ state }}</p>
<button @click="myFn">按钮</button>
</template>
<script setup>
import { reactive, ref, toRaw } from 'vue';
let state = reactive({ name: 'lnj', age: 18 });
// 获取state的源数据
let obj2 = toRaw(state);
function myFn() {
// 获取的源数据更改,不会触发页面更新
obj2.name = 'zs';
console.log(obj2); // {name: "zs", age: 18}
}
</script>
shallowReactive
shallowReactive监听了第一层属性的值,一旦发生改变,则更新视图;其他层,虽然值发生了改变,但是视图不会进行更新- 相当于只对第一层做了
proxy代理 - 如果有一个对象数据, 结构比较深, 但变化时只是外层属性变化,使用
shallowReactive
<template>
{{ state }}
<br />
<br />
<button @click="change1">更新 state.a 的值</button>
<br />
<br />
<button @click="change2">更新 state.first 下嵌套属性的值</button>
</template>
<script setup>
import { shallowReactive } from 'vue';
const obj = {
a: 1,
first: {
b: 2,
second: {
c: 3,
},
},
};
const state = shallowReactive(obj);
function change1() {
state.a = 7;
}
function change2() {
state.first.b = 8;
state.first.second.c = 9;
console.log(state);
}
</script>
shallowReadonly
shallowReadonly 设置了第一层属性的值为只读,其他层可以修改
<template>
{{ state }}
<br />
<br />
<button @click="change1">更新 state.a 的值</button>
<br />
<br />
<button @click="change2">更新 state.first 下嵌套属性的值</button>
</template>
<script setup>
import { shallowReactive } from 'vue';
const obj = {
a: 1,
first: {
b: 2,
second: {
c: 3,
},
},
};
const state = shallowReactive(obj);
function change1() {
state.a = 7;
}
function change2() {
state.first.b = 8;
state.first.second.c = 9;
console.log(state);
}
</script>

还没有留言,来发表第一条吧~