What is the trigger condition of vue. watch

  • 2021-09-12 00:29:05
  • OfStack

Many people are used to using watch, but few people know the real trigger condition of watch. If you don't know the principle of vue like the back of your hand, please use watch carefully.

Example 1, will watch be triggered below?


<script>
 new Vue({
 data() {
  return {
  city: {id: 1, name: 'Beijing'}
  }
 },
 watch: {
  city() {
  console.log('city changed')
  }
 },
 created() {
  this.city = {id: 1, name: 'Beijing'}
 }
 })
</script>

Triggered, because city is re-assigned an object in created method, and the pointing before and after city is different

Example 2:


<script>
 new Vue({
 data() {
  return {
  city: {id: 1, name: 'Beijing'}
  }
 },
 watch: {
  city() {
  console.log('city changed')
  }
 },
 created() {
  this.city.name = 'Shanghai'
 }
 })
</script>

Does not trigger because the direction of city does not change after the created method is executed

If we expect to capture this update, we should write the code like this:


watch: {
 city: {
  handler: () => console.log('city changed'),
  deep: true
 }
}

Setting the option deep to true allows vue to capture changes within the object.

The following discusses watch1 arrays under 1:


<script>
new Vue({
 el: '#body',
 data() {
  return {
   cities: ['Beijing', 'Tianjin']
  }
 },
 watch: {
  cities() {
   console.log('cities changed')
  }
 }
})
</script>

Which of the following actions will trigger the watch callback of cities?


this.cities = ['Beijing', 'Tianjin']
this.cities.push('Xiamen')
this.cities = this.cities.slice(0, 1)
this.cities.pop();
this.cities.sort((a,b)=>a.localeCompare(b));
this.cities[0] = 'Shenzhen'
this.cities.splice(0, 1)
this.cities.length = 0

The answer is that only the last three lines will not trigger.

Additional knowledge: vue depth watch and watch immediately trigger callback

Basic usage

When the search box inputs search keywords, it can automatically trigger the search. At this time, in addition to listening for change events in the search box, we can also listen for changes in search keywords through watch.


<template>
 <div>
  <span> Search </span>
  <input v-model="searchVal" />
 </div>
</template>
<script>
export default {
 data() {
 return {
  searchVal: ''
 }
 },
 watch: {
 //  After the value changes, reload the data 
 searchVal(newValue, oldValue) {
  if (newValue !== oldValue) {
  this.loadData()
  }
 }
 },
 methods: {
 loadData() {
  //  Reload data, which requires function anti-shake 
 }
 }
}
</script>

Trigger immediately

With the above code, it is now possible to trigger loading data when the value changes, but if we want to load data when the page is initialized, we need to call the loadData method again in the created or mounted life cycle hook. Now, however, instead of writing like this, it can be satisfied by configuring the immediate trigger property of watch.


export default {
 watch: {
 //  After the value changes, reload the data 
 searchValue: {
 //  Pass handler To listen for attribute changes ,  Initial call  newValue For "" Empty string,  oldValue For  undefined
  handler(newValue, oldValue) {
  if (newValue !== oldValue) {
   this.loadData()
  }
  },
  //  Configure immediate execution properties 
  immediate: true
 }
 }
}

Depth monitoring

1 form page, the requirement is that after the user modifies any one item of the form, the form page needs to be changed to the modified state. If we follow the writing of watch in the above example, then we need to listen to every attribute of the form, which is too troublesome. At this time, we need to use the depth of watch to listen to deep


export default {
 data() {
 return {
  formData: {
  name: '',
  sex: '',
  age: 0,
  deptId: ''
  }
 }
 },
 watch: {
 //  After the value changes, reload the data 
 formData: {
  //  It should be noted that because of object references,  newValue And oldValue Value of 1 Straight equality 
  handler(newValue, oldValue) {
  //  Mark page editing status here 
  },
  //  By specifying deep Property is true, watch Will listen to every object 1 Change of value 
  deep: true
 }
 }
}

Listen at any time, cancel at any time, and learn about $watch under 1

There is such a requirement, there is a form, when editing, you need to monitor the changes of the form. If there is a change, the Save button is enabled, otherwise the Save button is disabled.

At this time, for the newly added form, you can directly monitor the form data through watch (assuming formData), as mentioned in the above example, but for editing the form, the form needs to backfill the data. At this time, the value of formData will be modified, and watch will be triggered, so it is impossible to accurately judge whether to enable the save button. Now you need to know $watch for 1 time


export default {
 data() {
 return {
  formData: {
  name: '',
  age: 0
  }
 }
 },
 created() {
 this.$_loadData()
 },
 methods: {
 //  Simulate asynchronous request data 
 $_loadData() {
  setTimeout(() => {
  //  Assign value first 
  this.formData = {
   name: ' Zi Jun ',
   age: 18
  }
  //  After the form data is backfilled, listen for whether the data changes 
  const unwatch = this.$watch(
   'formData',
   () => {
   console.log(' The data has changed ')
   },
   {
   deep: true
   }
  )
  //  The simulation data has changed 
  setTimeout(() => {
   this.formData.name = ' Zhang 3'
  }, 1000)
  }, 1000)
 }
 }
}

As you can see from the above example, we can monitor data changes through this. $watch when needed. So how to cancel listening? In the above example, this. $watch returns a value unwatch, which is a function. When you need to cancel, you can cancel it by executing unwatch ()


Related articles: