Skip to content

使用 ref 和 reactive 的一个小坑(可能会改变原数据)

偶然一次,我定义了一个数组 list,想复用它。然后将它用 reactive 包裹过后,并往返回的响应式数据添加数据,这时我发现最初定义的数组 list 发生了改变。 情况有点像下面这样子。

js
import { reactive, toRaw } from 'vue';

const list = [1,2]
const list2 = reactive(list)
list2.push(3)

// [1,2,3]   [1,2,3]
console.log(list, toRaw(list2));

于是我结合官网的说明,是这样的情况:

reactive 只能包裹对象。如果是以一个变量作为参数传入,那么操作返回的响应式数据的时候这个变量也会跟着改变。 不仅仅是 reactive,ref 传入的参数如果也是一个引用数据类型,那么操作返回的响应式数据的时候,只要不是全量替换,那么原数据也是会跟着改变的。 就算全部替换掉也不会失去响应式,不像 reactive。比如如下:

js
import { reactive, toRaw } from 'vue';

const list = [1,2]
const list2 = ref(list)
list2.value.push(3)

// 完全替换掉也不会失去响应式
list2.value = [0]
// 此时 list2.value 就变成了 [0]。而 list 打印的是 [1,2,3]
console.log(list2.value, list);

最后回到那个我想复用 list 的问题,此时我就必须克隆一份新的数据。 这时候再改变 list2,list 的值也不会改变了。

js
const list2 = reactive(JSON.parse(JSON.stringify(list)))

最最后我想说的是,这可能只是一个小小的问题。。只是平时写代码很少注意注意到这点。所有以后就要注意了,如果定义了一个应用数据的变量,并且将它传参进 reactive 或 ref, 那么除非 ref 全部替换掉,操作返回的响应式时,最初的引用数据也是会跟着改变的

Released under the MIT License.