返回

逐层剥开Vue3 Computed set函数不触发的谜团

前端

Vue 3 中计算属性的 set 函数:理解其行为和解决方法

什么是计算属性?

在 Vue 3 中,计算属性是一种派生属性,它基于其他属性的值进行计算。当这些依赖属性发生变化时,计算属性将自动更新。

set 函数的工作原理

计算属性有一个可选的 set 函数,当属性值被分配新值时,该函数会被调用。set 函数允许我们对计算属性值进行响应,从而可以执行一些操作或副作用。

set 函数未触发的原因

在某些情况下,计算属性的 set 函数可能不会被触发,导致界面上的数据无法及时更新。以下是一些常见原因:

原因一:直接修改对象属性

Vue 3 中的对象属性是引用类型,这意味着对对象属性的直接修改不会触发计算属性的 set 函数。

示例:

const data = ref({
  name: 'John'
})

const computedName = computed(() => {
  return data.value.name
})

// 不会触发 computedName 更新
data.value.name = 'Jane'

解决方案:

可以使用 set 方法修改对象属性,从而触发计算属性的 set 函数。

data.value.name = 'Jane' // 不会触发 computedName 更新

// 使用 set 方法
data.value.name = 'Jane' // 触发 computedName 更新

原因二:子组件中对父组件数据的修改

当子组件通过 v-model 绑定父组件的数据时,子组件对该数据的修改不会触发父组件中计算属性的 set 函数。

示例:

<template>
  <ChildComponent :data="data" />
</template>

<script>
const data = ref({
  name: 'John'
})

const computedName = computed(() => {
  return data.value.name
})
</script>
<template>
  <input v-model="data.name" />
</template>

<script>
export default {
  props: ['data']
}
</script>

解决方案:

可以使用 sync 修饰符来传递数据,以便子组件对父组件数据的修改能够触发父组件中计算属性的 set 函数。

<template>
  <ChildComponent :data.sync="data" />
</template>

<script>
const data = ref({
  name: 'John'
})

const computedName = computed(() => {
  return data.value.name
})
</script>

原因三:使用 Object.assign() 或展开运算符

当使用 Object.assign() 或展开运算符来修改对象时,不会触发计算属性的 set 函数。

示例:

const data = ref({
  name: 'John'
})

const computedName = computed(() => {
  return data.value.name
})

// 不会触发 computedName 更新
data.value = Object.assign({}, data.value, { name: 'Jane' })

解决方案:

应使用 set 方法或 Object.defineProperty() 来修改对象,从而触发计算属性的 set 函数。

使用 set 方法:

data.value = { ...data.value, name: 'Jane' }

使用 Object.defineProperty()

Object.defineProperty(data.value, 'name', { value: 'Jane' })

结论

了解计算属性 set 函数的行为和解决方法对于构建可靠且高效的 Vue 3 应用程序至关重要。通过解决上述原因,您可以确保计算属性的 set 函数在需要时被触发,从而确保界面的数据始终是最新的。

常见问题解答

Q1:何时应该使用计算属性的 set 函数?

A:当您需要在属性值发生变化时执行一些操作或副作用时,可以使用 set 函数。

Q2:为什么子组件对父组件数据的修改不会触发父组件中计算属性的 set 函数?

A:这是因为在默认情况下,子组件对父组件数据的修改不会导致父组件数据更新。需要使用 sync 修饰符或 provide/inject 来实现数据同步。

Q3:如何使用 Object.defineProperty() 来修改对象?

A:使用 Object.defineProperty() 来修改对象时,需要指定三个参数:对象、属性名称和属性符。

Q4:set 函数的第一个参数是什么?

A:set 函数的第一个参数是新值。

Q5:如何在 set 函数中获取当前值?

A:可以使用 this 来访问当前值。