使用 vue3 赋值后视图没变化的问题
问题:
环境
“vue”: “^3.4.29”,
“vue-draggable-plus”: “^0.5.3”,
如果 baseModuleList 是一个 ref,如下:
export const baseModuleList = ref([1,2,3])
并且你这样写:
const list1 = ref<any>(baseModuleList);
这样会导致的一个问题,当你只是修改了顺序,如 [1,2,3] 变成了 [3,2,1], 然后当你再试图去初始化 list1 为 [1,2,3] 时视图上不会有任何变化。
// 以下代码不会使视图变化
list1.value = [...baseModuleList.value]
原因
list1 的值是 baseModuleList 这个 ref 对象本身,而不是它的值。而是引用了整个 ref 对象。
https://cn.vuejs.org/api/reactivity-core#ref
嵌套的 ref,它们将被深层地解包。
const list00 = ref<any>(baseModuleList)
const list11 = ref<any>(baseModuleList.value)
const list22 = ref<any>([...baseModuleList.value])
console.log("🚀 ~ initTemplateData ~ list00:", list00)
console.log("🚀 ~ initTemplateData ~ list11:", list11)
console.log("🚀 ~ initTemplateData ~ list22:", list22)
结果:这三种写法的输出结果都是一样的,如下图
包括 .value
的值也是一样的
对数组里面的值进行增删改,三种赋值的方法视图的变化都是符合期望的,除了上面“问题”当中出现的问题几乎没有什么不一样。
再进一步分析原因,就会发现当如下写的时候
const list1 = ref<any>(baseModuleList)
当 对 list1.value
修改时真正修改的是 baseModuleList
的值。所以 [...baseModuleList.value]
相当于 [...list1.value]
。
即便结构赋值后的是一个新数组但因为值没有发生变化所以视图也就没有变化。
list1.value = [...baseModuleList.value]
解决办法
正确的做法:直接引用值 baseModuleList.value
,应该这样写:
const list1 = ref<any>(baseModuleList.value);
// 或者
const list1 = ref<any>([...baseModuleList.value]);
如果希望 list1 与 baseModuleList 保持同步,可以使用计算属性:
import { ref, computed } from 'vue';
const baseModuleList = ref([
{ id: 1, name: '模块 A' },
{ id: 2, name: '模块 B' },
{ id: 3, name: '模块 C' },
]);
const list1 = computed(() => baseModuleList.value); // list1 始终与 baseModuleList.value 同步
总结
如果 baseModuleList 是一个 ref,直接将其赋值给另一个 ref 可能会导致一些不符合直觉的响应性的问题。
应该直接使用值 baseModuleList.value
来初始化 list1,或者使用计算属性来保持同步。
代码中尽量使用解构赋值去初始化值,避免影响原始数据,造成一些意外的问题,使代码变得复杂且不直观。