是什么导致 Vue computed 属性 被计算?
What's causing the Vue computed property to be computed?
我对计算属性的理解是,如果模板中未使用计算的 属性,则不应计算它。然而,当计算 属性 有一个观察者时,这个计算 属性 被评估。
我知道这不是理想的应用程序架构,但我的问题是,它以这种方式工作的事实是理想的 Vue 行为,还是现在实现方式的一些副作用,并且可以在未来的版本中改变?
或者换句话说:
如果计算的 属性 没有在模板中使用并且代码库中没有其他明确的 getter,除了观察者,是否应该评估它?
示例:
<template>
<div>
<button @click="counter++">+1</button>
{{ counter }}
</div>
</template>
<script>
export default {
name: "Main",
data() {
return {
counter: 0,
};
},
computed: {
notUsedInTemplate() {
console.log("notUsedInTemplate computed called");
return this.counter + 1;
},
},
watch: {
notUsedInTemplate() {
console.log("notUsedInTemplate watch called");
},
},
};
</script>
Link 到沙箱:https://codesandbox.io/s/computed-sandbox-ru3n3?file=/src/components/Main.vue:0-818
你对计算 属性 的看法是正确的。计算出的 属性 中的任何内容都将附加到 vue
实例并可在模板中访问。
所以,如果它没有在模板中使用,它不应该在计算中。
computed
属性是声明性的,其中 watch
是命令性的。
computed: {
// a computed getter
reversedMessage: function () {
// `this` points to the vm instance
return this.message.split('').reverse().join('')
}
}
最好的部分是我们以声明方式创建了这种依赖关系:计算的 getter 函数没有副作用,这使得它更容易测试和理解。
watch 是查找更改并更新值的函数。
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
通过使用计算 getter 属性 您只是让 vue
以声明方式跟踪更改和更新变得容易,但是您可以使用 watch
但这是必要的,vue 需要查找更改,每个更改都需要触发函数调用并稍后执行该函数。
如果模板中未使用计算的 属性,则不应计算它
...不正确。正确的说法是:
如果未使用(任何地方)计算的 属性,则不应对其进行评估
使用 watch
计算 属性。其实watch
和模板重渲染很像(在vue 3中重渲染其实没什么特别的watchEffect)
因为要看(任何东西):
- Vue 1st 需要 运行 代码 - 在本例中
notUsedInTemplate
getter - 以找出它正在访问的反应数据(因此 this.counter
被跟踪为依赖)
- 当
this.counter
改变时,watcher 运行 再次发送 notUsedInTemplate
getter 以便它可以将新值与之前的值进行比较
- 如果值发生变化,它 运行 是回调(在您的示例中记录)
所以回答问题:
- 是的,这是期望的行为,因为您的观察者不会跟踪
notUsedInTemplate
计算的 属性 的变化,而是它用来计算其值的基础数据
- Watcher 正在访问计算的 属性,无需在其他任何地方使用它
好的,更多细节为什么这样工作
Vue 反应总是有两个阶段:
- 阶段 1 - 运行 代码(模板或 watch expression/fn)并收集所有依赖项(例如,代码“触及”的任何反应数据)
- 阶段 2 - 跟踪依赖关系。如果任何依赖项发生变化,重新运行 回调(或渲染函数)
请参阅文档中的这一章 - How Changes Are Tracked - the example is explicitly mentioning only template re-rendering (which uses watcher created by Vue itself) but all of this applies to all watchers 包括用户创建的那些
我对计算属性的理解是,如果模板中未使用计算的 属性,则不应计算它。然而,当计算 属性 有一个观察者时,这个计算 属性 被评估。
我知道这不是理想的应用程序架构,但我的问题是,它以这种方式工作的事实是理想的 Vue 行为,还是现在实现方式的一些副作用,并且可以在未来的版本中改变?
或者换句话说: 如果计算的 属性 没有在模板中使用并且代码库中没有其他明确的 getter,除了观察者,是否应该评估它?
示例:
<template>
<div>
<button @click="counter++">+1</button>
{{ counter }}
</div>
</template>
<script>
export default {
name: "Main",
data() {
return {
counter: 0,
};
},
computed: {
notUsedInTemplate() {
console.log("notUsedInTemplate computed called");
return this.counter + 1;
},
},
watch: {
notUsedInTemplate() {
console.log("notUsedInTemplate watch called");
},
},
};
</script>
Link 到沙箱:https://codesandbox.io/s/computed-sandbox-ru3n3?file=/src/components/Main.vue:0-818
你对计算 属性 的看法是正确的。计算出的 属性 中的任何内容都将附加到 vue
实例并可在模板中访问。
所以,如果它没有在模板中使用,它不应该在计算中。
computed
属性是声明性的,其中 watch
是命令性的。
computed: {
// a computed getter
reversedMessage: function () {
// `this` points to the vm instance
return this.message.split('').reverse().join('')
}
}
最好的部分是我们以声明方式创建了这种依赖关系:计算的 getter 函数没有副作用,这使得它更容易测试和理解。
watch 是查找更改并更新值的函数。
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
通过使用计算 getter 属性 您只是让 vue
以声明方式跟踪更改和更新变得容易,但是您可以使用 watch
但这是必要的,vue 需要查找更改,每个更改都需要触发函数调用并稍后执行该函数。
如果模板中未使用计算的 属性,则不应计算它
...不正确。正确的说法是:
如果未使用(任何地方)计算的 属性,则不应对其进行评估
使用 watch
计算 属性。其实watch
和模板重渲染很像(在vue 3中重渲染其实没什么特别的watchEffect)
因为要看(任何东西):
- Vue 1st 需要 运行 代码 - 在本例中
notUsedInTemplate
getter - 以找出它正在访问的反应数据(因此this.counter
被跟踪为依赖) - 当
this.counter
改变时,watcher 运行 再次发送notUsedInTemplate
getter 以便它可以将新值与之前的值进行比较 - 如果值发生变化,它 运行 是回调(在您的示例中记录)
所以回答问题:
- 是的,这是期望的行为,因为您的观察者不会跟踪
notUsedInTemplate
计算的 属性 的变化,而是它用来计算其值的基础数据 - Watcher 正在访问计算的 属性,无需在其他任何地方使用它
好的,更多细节为什么这样工作
Vue 反应总是有两个阶段:
- 阶段 1 - 运行 代码(模板或 watch expression/fn)并收集所有依赖项(例如,代码“触及”的任何反应数据)
- 阶段 2 - 跟踪依赖关系。如果任何依赖项发生变化,重新运行 回调(或渲染函数)
请参阅文档中的这一章 - How Changes Are Tracked - the example is explicitly mentioning only template re-rendering (which uses watcher created by Vue itself) but all of this applies to all watchers 包括用户创建的那些