Vue没有根据方法更新计算属性,但是直接调用时相同的方法返回正确的值
Posted
技术标签:
【中文标题】Vue没有根据方法更新计算属性,但是直接调用时相同的方法返回正确的值【英文标题】:Vue not updating computed property based on a method, but the same method returns correct value when called directly 【发布时间】:2020-11-30 01:08:45 【问题描述】:我有一个用于提交表单的简单按钮组件,单击它时应该会给出一些反馈:在提交表单时显示一个微调器并禁用按钮,如果返回任何错误,也保持禁用它从服务器直到错误被清除(通过更改包含错误的字段的输入来清除错误)。
这是组件的模板:
<template>
<button type="submit" :disabled="disabled">
<loading-spinner v-if="submitting"></loading-spinner>
<slot>Submit</slot>
</button>
</template>
<script>
export default
props:
form:
type: Object,
required: true
,
created()
// Globally available event handler which listens for events
// emitted by Form object - it works fine
Event.$on('submitting', () => this.submitting = true);
Event.$on('submitted', () => this.submitting = false);
,
data()
return
submitting: false,
,
computed:
// Here is the problem: this.form.errors.any() doesn't get updated in the
// computed prop even when errors are cleared. This same method, however,
// returns correct result when called directly via a test button
disabled()
return this.submitting || this.form.errors.any()
,
// doesn't get updated either - apparently
// errors()
// return this.form.errors.any()
//
,
</script>
按钮将Form
对象传递给它,因此它也可以访问Errors
对象,该对象具有一些方便的方法来管理错误。作为 prop 传递的 Form
对象在 submit-button
组件内是响应式的,当我在表单中(在父组件上)键入时,它的字段会在 Vue Devtools 中更新,但计算出来的 prop(disabled
或 errors
) 依赖它不会得到更新。
当我提交带有错误数据的表单时,我得到了错误,所以form.errors.any()
返回真。但是,一旦第一次返回错误,按钮就会被禁用并像那样“冻结”(form.errors.any()
会一直返回 true,即使它不是)。
我知道计算的 props 被缓存了,但是根据定义,当它们的依赖更新时它们应该更新(在这种情况下,计算属性 disabled
应该更新,因为 this.form.errors.any()
已更新)。但是,提交按钮组件似乎“忽略”了其计算属性中 this.form.errors.any()
的更新(一旦出现错误,它就会一直返回 true,并且永远不会更新)。如果我在父组件上创建相同的计算属性,也会发生同样的事情。
其他信息
当我手动检查其值时(例如,通过调用 form.errors.any()
的按钮),它每次都会将正确的值记录到控制台,但它不会在我的计算属性中得到更新。
Errors
对象上的 any()
方法 - 这里没什么特别的
any()
return Object.keys(this.errors).length > 0;
Form 和 Errors 对象都可以正常工作:它们的方法在从任何组件直接调用(例如通过按钮单击)时返回正常值,并且它们按预期调度事件,它们只是不对计算的 prop 做出反应。
解决方法
我的解决方案是使用方法而不是计算属性,但它有点过于冗长,我最想知道为什么在这种情况下我不能使用更优雅的计算属性?
<template>
<button type="submit" :disabled="submitting || anyErrors()">
<loading-spinner v-if="submitting"></loading-spinner>
<slot>Submit</slot>
</button>
</template>
<script>
export default
...
methods:
anyErrors()
return this.form.errors.any()
</script>
【问题讨论】:
我会说这是由于以 Vue 无法检测到的方式改变对象引起的(请参阅docs)。您如何填充 Errors 对象中的错误?您是否正在向对象添加新属性? @DecadeMoon 错误是 Errors 类中的一个对象。但是,如果你问它,它不是 Vue 组件(因为我理解文档中的章节指的是那个)。this.errors
是实例化(构造函数)上的空对象,可以通过方法(get/register/clear 和已经提到的任何方法)访问/填充/清除它。
【参考方案1】:
您需要将 form.errors 属性放置在表单的 props 上,以使其开箱即用。否则,当您添加错误时,您必须使用Vue.set()
方法才能使其具有反应性。
所以你的 props 对象应该是这样的:
props:
form:
type: Object,
required: true,
errors: ,
,
更多信息: https://vuejs.org/v2/guide/reactivity.html
(编辑以使错误成为对象,如问题中所示,而不是数组)
【讨论】:
仍然不适用于计算属性。我还尝试仅传递错误对象(而不是整个表单,因为我实际上并不需要它,我只使用其中的错误)但它没有检测到它 你试过用Vue.set()
吗?看看我发布的链接。这对我来说仍然是一个反应性问题,因为数据在那里它只是没有在屏幕上更新。
嗨,@Ashley,是的,我试过了,但还是不行。这可能是因为我没有正确设置它。我应该在 created/mounted 生命周期挂钩中调用 this.$set 吗?据我了解,您调用要设置反应性的对象,给它一个属性和一个值。所以它应该看起来像:this.$set(this.form.errors, 'hasErrors', this.form.errors.any())?但是新的“hasErrors”属性仍然没有反应。我一定是在这里做错了什么,你愿意更彻底地解释一下吗?谢谢你,很抱歉这么晚才回复!以上是关于Vue没有根据方法更新计算属性,但是直接调用时相同的方法返回正确的值的主要内容,如果未能解决你的问题,请参考以下文章