vue3复杂函数直接赋值后,双向绑定失效

发布于 2023-12-06  139 次阅读


问题示例

import { reactive } from "vue";

const state = reactive({
  message: "Hello Vue3!",
});

在页面中绑定这个变量并展示:

<template>
  <div>{{ state.message }}</div>
</template>

如果我们对这个变量进行重新赋值:

state.message = "Hello World!";

控制台并没有抛出任何错误,但是页面上并没有更新,显示的仍然是原来的"Hello Vue3!",这意味着重新赋值失去了响应式。

解决方案

reactive

// 赋值新地址(失效)
let obj = reactive({
  name: [],
  age: ''
})
obj = data || {}
// 添加新属性(失效)
obj.xxxx = 'xxxx'
// 通用解决方法
// ref全量覆盖
let obj = ref({
  name: [],
  age: ''
})
obj = data || {}
// vue2.7
import { set } from 'vue'
set(obj, 'xxx', 'xxx')
// vue3.0
// Object.assign 
Object.assign(obj, data)

ref

// 未初始化(失效)(vue3.0无需初始化,双向绑定不失效)
let obj = ref({
  name: []
})
obj.value.age = 18
// vue2.7
// set
import { set } from 'vue'
set(obj.value, 'age', 18)
// 全量覆盖
obj.value = {
  age: 18
}
// or
obj.value = Object.assign({}, obj.value, { age: 18 })

除了set函数,还有一种方法可以解决这个问题,那就是使用toRef函数将响应式对象上的属性转化为一个ref对象,这样当重新赋值后,就会自动更新。示例如下所示:

import { reactive, toRef } from "vue";

const state = reactive({
  message: "Hello Vue3!",
});

const messageRef = toRef(state, "message");

messageRef.value = "Hello World!";

一沙一世界,一花一天堂。君掌盛无边,刹那成永恒。