【问题标题】:Why won't my template update with it being bound to a computed property?为什么我的模板不会在绑定到计算属性时更新?
【发布时间】:2021-09-10 23:42:42
【问题描述】:

我遇到了一个问题,我的组件中有一些模板 HTML,它依赖于 Vuex 方法的 computed getter。正如您在模板中看到的那样,我只是试图在带有{{ getNumSets }}<p> 标记中显示计算属性的输出。

当我使用 UPDATE_EXERCISE_SETS 突变更新状态时,我可以在 Vue devtools 中看到状态已正确更新,但更改未反映在 <p> {{ getNumSets }} </p> 部分中。

模板 HTML:

<template>
...
<v-text-field
   v-model="getNumSets"
   placeholder="S"
   type="number"
   outlined
   dense
></v-text-field>
<p>{{ getNumSets }}</p>
...
</template>

组件逻辑:

<script>
...
computed: {
   getNumSets: {
      get() {
         var numSets = this.$store.getters['designer/getNumSetsForExercise']({id: this.id, parent: this.parent})
         return numSets
      },
      set(value) {  // This correctly updates the state as seen in the Vue DevTools
        this.$store.commit('designer/UPDATE_EXERCISE_SETS', {
                    id: this.exerciseId,
                    parentName: this.parent,
                    numSets: parseInt(value),
                    date: this.date
                })
      }

}
...
</script>

Vuex 存储逻辑:

...
state: {
  designerBucket: []
},
getters: {
  getNumSetsForExercise: (state) => (payload) => {
    var numSets = 0
    for (var i = 0; i < state.designerBucket.length; i++) {
      if (state.designerBucket[i].id == payload.id) {
        numSets = state.designerBucket[i].numSets
      }
    }
    return numSets
  }
},
mutations: {
  UPDATE_EXERCISE_SETS(state, payload) {
    state.designerBucket.forEach(exercise => {
       if (exercise.id == payload.id) {
          exercise.numSets = payload.numSets
       }
    })
   }
}

非常感谢任何见解!

附:我还尝试使用for (var i=0...) 循环,遍历索引,然后使用Vue.set() 设置值。这确实也更新了 store 中的值,但计算的属性仍然没有更新模板。

【问题讨论】:

  • 在您的 Vuex getter 中,您是否尝试使用该语法将参数传递给 getter? Getters don't take arguments.
  • @zcoop98 我实际上忘记在问题中输入正确的参数,但我对其进行了编辑以反映它的实际外观。对不起!

标签: javascript vue.js vuetify.js vuex


【解决方案1】:

这变成了一个有点冗长的答案,但请耐心等待。

这是我的预感:由于您从 Vuex getter 返回一个 函数,因此 Vue 不会在状态更改时更新您的计算属性,因为 函数永远不会改变,即使从它返回的值会。这破坏了计算属性的缓存机制。


箭头函数获取器的反应性


在创建像这样的 getter 时要记住的一件事,您可以在其中返回箭头函数:

getNumSetsForExercise: (state) => (payload) => {
    var numSets = 0
    for (var i = 0; i < state.designerBucket.length; i++) {
        if (state.designerBucket[i].id == payload.id) {
        numSets = state.designerBucket[i].numSets
        }
    }
    return numSets
}

...是您不再从 getter 返回实际状态数据。

当您使用它从依赖于组件本地数据的状态中提取某些内容时,这非常棒,因为我们不需要 Vue 来检测更改,我们只需要访问当前状态的函数,这很好。

但是,它也可能导致认为更新状态应该更新 getter,而实际上并没有。这仅在我们尝试在示例中的计算属性中使用此 getter 时才真正重要,因为 computed 属性 跟踪它们的依赖关系缓存数据 .

计算缓存和依赖检测


在 Vue 中,computed 属性比最初看起来更智能。他们缓存他们的结果,他们注册和跟踪他们依赖的反应值,以知道何时使该缓存无效。

一旦 Vue 计算出一个计算属性的值,它就会在内部存储它,这样如果你再次调用该属性不改变依赖关系,该属性可以返回缓存的值而不是重新计算。

这里的关键是依赖检测——你的 getter 具有 Vue 检测到的三个依赖:

get() {
    var numSets = this.$store.getters['designer/getNumSetsForExercise']({id: this.id, parent: this.parent})
    return numSets
},
  1. 吸气剂:this.$store.getters['designer/getNumSetsForExercise']
  2. this.id
  3. this.parent

&lt;v-text-field&gt; 调用您的设置器时,这些值都不会发生变化

这意味着 Vue 没有检测到任何依赖项更改,而是返回缓存数据而不是重新计算。

如何解决?


通常,当您遇到这类依赖问题时,这是因为状态的设计可以得到改进,无论是通过将更多数据移动到状态中,还是通过某种方式对其进行重组。

在这种情况下,除非您绝对 需要 designerBucket 成为一个用于排序目的的数组,否则我建议将其设为 object,其中每个集合都是由id 存储。这将通过删除循环来简化实现,并且完全不需要你的 getter:

...
state: {
  designerBucket: {}
},
mutations: {
  UPDATE_EXERCISE_SETS(state, payload) {
    // Need to use $set since we're adding a new property to the object
    Vue.set(state.designerBucket, payload.id, payload.numSets);
  }
}

现在,无需调用 getter,只需从状态中拉出 designerBucket 并通过 this.id 直接访问:

<script>
...
computed: {
    getNumSets: {
    get() {
        return this.$store.state.designerBucket[this.id];
    },
    set(value) {
        this.$store.commit('designer/UPDATE_EXERCISE_SETS', {
            id: this.exerciseId,
            parentName: this.parent,
            numSets: parseInt(value),
            date: this.date
        });
    }
}
...
</script>

应该让 Vue 现在可以正确检测更改,并防止以前出现过时缓存问题。

【讨论】:

  • 很棒的答案,我采用了你的方法,它奏效了!谢谢@zcoop98,我接受了你的回答。另外,谢谢你让我学到了一些东西
【解决方案2】:

已编辑:首先在脚本标签顶部像这样从'vuex'导入mapGetters。

import { mapGetters } from "vuex"

现在在您的计算对象中,添加 mapGetters 并将参数传递给 get() 方法中的 getter 方法,如下所示:-

computed: {
   ...mapGetters('designer',['getNumSetsForExercise']),
   getNumSets: {
      get() {
         var numSets = this.getNumSetsForExercise({id: this.id, parent: this.parent})
         return numSets
      },
      set(value) {  // This correctly updates the state as seen in the Vue DevTools
        this.$store.commit('designer/UPDATE_EXERCISE_SETS', {
                    id: this.exerciseId,
                    parentName: this.parent,
                    numSets: parseInt(value),
                    date: this.date
                })
      }

}

然后看看它是否有效。

【讨论】:

  • 我用正确的 getter 方法参数更新了问题,很抱歉造成混乱!
  • @CameronRosier 我已经更新了答案,请立即查看。
猜你喜欢
  • 1970-01-01
  • 2018-07-29
  • 2012-04-06
  • 1970-01-01
  • 2018-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多