-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Computed values are not consistent in watch callback #5720
Comments
<script setup>
import { computed, ref, watch, nextTick } from 'vue';
const count = ref(0)
const plusOne = computed(() => {
console.log(Object.assign({},count))
console.log("computed",new Date().valueOf())
return count.value + 1
})
const log = []
watch(count, (newVal,oldVal) => {
console.log(newVal,oldVal)
log.push(`watch count: ${count.value}`)
// Here `computed` is not get the lastest value
log.push(`watch plusOne: ${plusOne.value}`)
console.log("watch",new Date().valueOf())
})
// Here `computed` is get the lastest value
log.push(`before inc plusOne: ${plusOne.value}`)
count.value++
// Here `computed` is get the lastest value
log.push(`after inc plusOne: ${plusOne.value}`)
</script>
<template>
<h1 v-for="line in log">{{ line }}</h1>
</template> |
This scenario should use |
Why should it? There is nothing in computed values documentation (that i know of) that suggests the current behaviour is expected. That effect example happens to work, but it looks like doing manually what computed values were designed to do for you. |
This only seems to happen when the change happens synchronously after the watcher has been defined. Doing the count increment in Without claiming a full understanding, it seems any trigger of the watch effect before the next flush leads to a synchronous call of the watcher callback, which is undesirable and IMHO unintended, so seems like a bug. #5721 Seems like another manifestation of the same problem. |
sorry, I misread. this should be a bug. import { computed, ref, watch,onMounted } from 'vue';
const count = ref(0)
const plusOne = computed(() => count.value + 1)
+plusOne.value // add this line ,make sure computed collect dependencies first
const log = []
watch(count, () => {
log.push(`watch count: ${count.value}`)
log.push(`watch plusOne: ${plusOne.value}`)
})
log.push(`before inc plusOne: ${plusOne.value}`)
count.value++
log.push(`after inc plusOne: ${plusOne.value}`) |
Version
3.2.33
Reproduction link
sfc.vuejs.org/
The absolute minimal test case that prints to console:
Steps to reproduce
Look at the printed output, notice the value printed with label "watch plusOne".
What is expected?
Computed values should recompute after its dependency is updated. That update should be immediately visible in the watch handler.
Expected output:
What is actually happening?
Computed value is not reevaluated on read, even though the dependency have been changed since last read.
Actual output:
This behaviour is a root cause for data inconsistencies in called code, as part of the data is current, and part is outdated. The watch callbacks are often used to perform external effects, and those effects end up operating on stale data.
The workaround in this specific case would be to watch the "plusOne" computed value instead. It becomes more complex when the refs and computed values are scattered across different functions or there are more complex computed value chains.
The text was updated successfully, but these errors were encountered: