Watchers
While computed properties are more appropriate in most cases, sometimes a custom watcher is required. This is why Vue provides a more general way to respond to changes in data through the watch option. This is useful when you want to perform asynchronous operations or overhead operations when data changes.
Everyone should be familiar with watch, and the following writing method has been used in the project:
watch: { someProp () { // do something } } // orwatch: { someProp: { deep: true, handler () { // do something } } }
The above writing method tells vue that I need to listen for changes in someProp attributes, so vue will create a watcher object for us internally. (For space limitations, we don’t talk about the specific implementation of watcher. If you are interested, you can read it directlySource code watcher)
However, in vue, the function of watcher is not so single, let’s start with the code:
<template> <div> <p>a: {{ a }}</p> <p>b: {{ b }}</p> <button @click="increment">+</button> </div> </template> <script> export default { data () { return { a: 1 } }, computed: { b () { return * 2 } }, watch: { a () { ('a is changed') } }, methods: { increment () { += 1 } }, created () { (this._watchers) } } </script>
Online demo
The above code is very simple. We are now focusing on this._watchers printed in the created hook, as follows:
Expand three watchers separately and observe each expression, from top to bottom:
b() { return * 2;↵ } "a" function () { vm._update(vm._render(), hydrating);↵ }
The above three watchers represent three different functions of watchers, which we divide into three categories according to their functions:
- The watcher defined in the watch, used to listen for property changes (second)
- Watcher for the computed property (first)
- Watcher for page update (third)
normal-watcher
What we define in watch are of this type, that is, as long as the listening attributes change, the defined callback function will be triggered
computed-watcher
Each computed property will eventually generate a corresponding watcher object, but this type of watcher has a feature. Let's take b above as an example:
Property b depends on a. When a changes, b will not be recalculated immediately. It will only be truly calculated when b needs to be read in other places, that is, it has the lazy (lazy calculation) feature.
render-watcher
Each component will have one render-watcher, function () {↵ vm._update(vm._render(), hydrating);↵ }
, when data/computed
When the property in the file changes, the render-watcher will be called to update the component's view
The execution order of three watchers
In addition to the functional differences, these three watchers also have fixed execution orders, namely:
computed-render -> normal-watcher -> render-watcher
There is a reason for this arrangement, so as to ensure that when updating the component view, the computed property is already the latest value. If the render-watcher is ranked in front of the computed-render, the computed value will be the old data when the page is updated.
Let's take a look at the watcher in vue from an example code
In this example, using the watch option allows us to perform asynchronous operations (access an API), limiting how often we perform the operation, and setting the intermediate state before we get the final result. This is something that the computed attribute cannot do.
<div > <p> Ask a yes/no question: <input v-model="question"> </p> <p>{{ answer }}</p> </div> <!-- Since there is already a rich ecosystem of ajax libraries --> <!-- and collections of general-purpose utility methods, Vue core --> <!-- is able to remain small by not reinventing them. This also --> <!-- gives you the freedom to just use what you're familiar with. --> <script src="/[email protected]/dist/"></script> <script src="/[email protected]/"></script> <script> var watchExampleVM = new Vue({ el: '#watch-example', data: { question: '', answer: 'I cannot give you an answer until you ask a question!' }, watch: { // If the question changes, this function will runquestion: function (newQuestion) { = 'Waiting for you to stop typing...' () } }, methods: { // _.debounce is a function that limits the frequency of operations through lodash. // In this example, we want to limit the frequency of access to /api // Ajax request will not be issued until the user has entered it. // Learn more about _.debounce function (and its cousin// _.throttle), reference: /docs#debouncegetAnswer: _.debounce( function () { var vm = this if (('?') === -1) { = 'Questions usually contain a question mark. ;-)' return } = 'Thinking...' ('/api') .then(function (response) { = _.capitalize() }) .catch(function (error) { = 'Error! Could not reach the API. ' + error }) }, // This is the number of milliseconds we stop entering for the user to wait500 ) } }) </script>
summary
This article is not a source code analysis article, but just talks about things that seem irrelevant (computed/watch/page update), but have close connections inside. I hope it can lead to the inspiration and let everyone explore vue more deeply