一、问题来源
解构赋值是 ECMAScript 6 (ES6) 引入的一个非常方便的功能,通过它可以让我们以更简洁的方式从数组或对象中提取值,并将它们赋给变量。
但是如果我们使用解构赋值获取响应式对象中的属性后,再去修改这个属性,会失去响应式,例如
javascriptimport { reactive } from 'vue'; const state = reactive({ count: 0 }); let { count } = state; count = 1;
在上面的代码中,修改count后视图不会发生变化。
二、问题分析
在vue3中使用了Proxy来创建响应式对象,当我们将一个响应式对象的属性赋值或解构到一个本地变量时,访问或赋值该变量是非响应式的,因为它将不再触发源对象上的 get / set 代理。
简单的说,我们在使用解构赋值后,让我们实现响应式的Proxy,没了。
顺带介绍一下Proxy:Proxy 是 ES6 中引入的一种特殊对象,它可以作为目标对象的代理,用来拦截并控制对目标对象的操作,如访问、修改属性等。
三、解决办法
vue3中提供了这样一个API:
toRefs():将一个响应式对象转换为一个普通对象,这个普通对象的每个属性都是指向源对象相应属性的 ref。
也就是说,toRefs()接收一个响应式对象作为输入,然后返回一个新的对象。这个新对象的结构与输入的响应式对象相同,但其所有属性都被转换成了ref形式,也就是说,每个属性都变成了一个可以通过.value访问的响应式属性。这样我们就可以维持住这些属性的响应式了,因为它们都是新的响应式对象。
javascript
import { reactive, toRefs } from 'vue';
// 创建一个响应式对象
const state = reactive({
count: 0,
message: 'Hello Vue!'
});
// 使用 toRefs 将响应式对象转换为具有 ref 属性的新对象
const stateRefs = toRefs(state);
// 解构赋值,这里的 count 和 message 是 ref 类型
const { count, message } = stateRefs;
// 修改 ref 的值,这将触发响应式更新
count.value++;
message.value = 'Updated message';
// 这些修改将被 Vue 的响应式系统捕捉,导致视图更新