返回

Vue计算属性不更新?两招解决响应式依赖难题

vue.js

计算属性未因响应式依赖更新

在使用Vue构建应用程序时,经常会用到计算属性。这些属性能够基于其他响应式数据自动计算并更新。 但有时,你可能发现计算属性没有按照预期响应其依赖数据的变化而更新,正如上面的例子所示。本篇文章将分析这个问题并提供可行的解决方法。

问题剖析

以上面Student类和StudentComponent组件为例,问题的根源在于,计算属性的响应式依赖并未与组件内的响应式数据正确关联。 Student 类实例 student 被传递到组件中。组件内部使用了ref(props.data) 创建了一个 dataRef。这导致dataRef仅仅是在组件创建的时候获取了student的一个浅拷贝,而不是student对象本身。dataRef.age 被按钮的点击事件修改后, student对象的age实际上并没有被修改。因此,Student类里面的计算属性 adult并不会重新计算。Vue 的计算属性机制依赖响应式数据的变化,而不是普通的对象属性值。

解决方案

这里有几种方式解决这个问题。

1. 使用 toRefs 解构响应式对象

我们可以使用 vue 提供的 toRefs 方法将一个响应式对象转换为一组响应式引用。通过解构 toRefs(props.data) 返回的对象,我们能直接访问到响应式对象中的属性。这将确保组件的模板可以直接访问 Student 对象的响应式属性,并能够随之更新。

代码示例:

<script setup lang="ts">
import { toRefs } from 'vue';

const props = defineProps<{
    data: any
}>();

const { age, adult } = toRefs(props.data);


</script>

<template>
    <div>age: {{ age }}</div>
    <div>adult: {{ adult }}</div>
    <button @click="age++;">+1</button>
    <button @click="age--;">-1</button>
</template>

操作步骤:

  1. 在组件内引入toRefs
  2. setup 中解构 props.data。 这样直接操作解构出的age, 就能够修改student对象的age值,并且触发计算属性更新。
  3. 更新模板以使用解构出来的 ageadult 属性。

这种方法的优势在于代码更简洁直接,将原始对象的响应式属性直接暴露给组件使用。

2. 在类内部使用 ref 包裹基础属性

我们可以对类里的基础数据进行 ref 包裹。这样做可以让它们变成响应式数据。同时,我们在计算属性中使用解构,以保证正确监听。这样当数据发生改变时,依赖于该数据的计算属性会自动更新。

代码示例:

// Student.ts
import { computed, ref, type ComputedRef } from "vue";

export class Student {
    age:  any
    adult: ComputedRef<boolean>;

    constructor(age: number) {
       this.age = ref(age)
        
        this.adult = computed(() =>  this.age.value >= 18);
    }
}
// StudentComponent.vue
<script setup lang="ts">
import { defineProps, ref } from 'vue';
import {  } from './student';

const props = defineProps<{
  data: any;
}>();

const dataRef = ref(props.data);

</script>
<template>
    <div>age: {{ dataRef.value.age }}</div>
    <div>adult: {{ dataRef.value.adult }}</div>
    <button @click="dataRef.value.age++;">+1</button>
     <button @click="dataRef.value.age--;">-1</button>
</template>

操作步骤:

  1. Student.ts里使用 ref() 包裹类中的 age属性。同时,计算属性访问的时候加上 .value 获取具体的值,这可以让数据响应起来。
  2. StudentComponent.vue中使用 ref() 获取data 并且在模板和点击事件中访问的时候需要使用 dataRef.value.age来获取并设置值,否则,将还是只操作拷贝值。

这种方法对类本身进行了调整,增加了代码的复杂度, 但可以让 Student 类的行为更接近 Vue 的响应式数据模型。

安全提示

无论选择哪种解决方案,都应注意确保修改数据的操作符合业务逻辑, 并且避免出现预期外的数据变动。此外,合理规划数据传递方式也很关键, 以降低未来维护代码的难度。

这些解决方案展示了处理Vue中计算属性依赖问题的方式。通过使用 toRefs 或在类中使用 ref 包裹属性,可以正确地将响应式数据关联到计算属性,从而确保用户界面的正确更新。请选择最适合你的项目需求的方法。