Vue: Watchers
2022-03-21
0. Intro
The Why
Computed property 可以让我们去计算 derived values,但有时候我们需要 react to state changes,比如 mutating the DOM, or changing another piece of state based on the result of an async operation.
我们可以通过使用 options API 里面的 watch option 来触发 function,触发事件可以是 reactive property change。
Shallow vs Deep - Example 3
默认的 watch 是 shallow: callback will only trigger when the watched property has been assigned a new value - it won’t trigger on nested property changes.
如果要 watch all nested mutations, 就要用 deep watcher - 注意这个可能会影响 performance。
Deep watch requires traversing all nested properties in the watched object, and can be expensive when used on large data structures. Use it only when necessary and beware of the performance implications.
Lazy vs Eager - Example 4
Lazy (default): the callback won’t be called until the watched source has changed.
Eager: in some cases we may want the same callback logic to be run eagerly - for example, we may want to fetch some initial data, and then re-fetch the data whenever relevant state changes.
We can force a watcher’s callback to be executed immediately by declaring it using an object with a handler
function and the immediate: true
option.
Callback Flush Timing - Example 5
当你 mutate reactive state 的时候,可能会同时触发 Vue component updates 和 watcher callbacks created by you.
默认:user-created watcher callbacks are called before Vue component updates.
- This means if you attempt to access the DOM inside a watcher callback, the DOM will be in the state before Vue has applied any updates.
改变 timing:If you want to access the DOM in a watcher callback after Vue has updated it, you need to specify the flush: 'post'
option.
this.$watch()
- Example 6
我们也可以用 $watch()
instance method 来 create watchers。
适用场景:
- 想要根据条件 set up watcher
- 只有在 user 做了某些行为之后才加 watcher
- 想要早点 stop watcher
This is useful when you need to conditionally set up a watcher, or only watch something in response to user interaction. It also allows you to stop the watcher early.
停止 watcher - Example 7
用 watch option 或者 $watch()
method 定义的 watcher 会自动在 component unmounted 之后 stop,所以大部分时候你不需要手动停止它。
假如你需要在 unmount 之前停止 watcher,可以使用 unwatch() function.
1. Examples
Example 1
<p>
Ask a yes/no question:
<input v-model="question" />
</p>
<p>{{ answer }}</p>
export default {
data() {
return {
question: '',
answer: 'Questions usually contain a question mark. ;-)'
}
},
watch: {
// whenever question changes, this function will run
question(newQuestion, oldQuestion) {
if (newQuestion.indexOf('?') > -1) {
this.getAnswer()
}
}
},
methods: {
async getAnswer() {
this.answer = 'Thinking...'
try {
const res = await fetch('https://yesno.wtf/api')
this.answer = (await res.json()).answer
} catch (error) {
this.answer = 'Error! Could not reach the API. ' + error
}
}
}
}
Example 2
我们也可以用 dot-delimited path as the key of the watch object.
export default {
watch: {
// Note: only simple paths. Expressions are not supported.
'some.nested.key'(newValue) {
// ...
}
}
}
Example 3 - Deep Watcher
export default {
watch: {
someObject: {
handler(newValue, oldValue) {
// Note: `newValue` will be equal to `oldValue` here
// on nested mutations as long as the object itself
// hasn't been replaced.
},
deep: true
}
}
}
Example 4 - Eager Watchers
export default {
// ...
watch: {
question: {
handler(newQuestion) {
// this will be run immediately on component creation.
},
// force eager callback execution
immediate: true
}
}
// ...
}
Example 5 - Callback Flush Timing
export default {
// ...
watch: {
key: {
handler() {},
flush: 'post'
}
}
}
Example 6 - $watch()
export default {
created() {
this.$watch('question', (newQuestion) => {
// ...
})
}
}
Example 7 - stop a watcher
const unwatch = this.$watch('foo', callback)
// ...when the watcher is no longer needed:
unwatch()