【Vue】Deeply explore the principles of calculation and listening properties

Hello, I am Xiao Suoqi. The carefully crafted Vue series tutorials are continuously updated, covering a large number of experiences and examples. They are explained from the shallower to the deeper. If you want to learn & consolidate & avoid pitfalls, let’s learn together~

Computed and listening properties

Computed properties

Summary of key points

Definition: The attribute to be used does not exist and needs to be calculated from existing attributes.

Principle: The bottom layer uses the getters and setters provided by the Objcet.defineproperty() method to calculate properties. The calculated properties will automatically find the getter and call it, and get the return value and put it on the VM.

About get function

  • get will be executed once when reading for the first time.

  • It will be called again when the dependent data changes.

  • Compared with the methods implementation, there is an internal caching mechanism. When we call get again, the cache is used directly, which is more efficient. Computed is also directly displayed during debugging.

So what happens when we need to change the value?

  • The computed properties will eventually appear on the VM, and you can use this to read and use them.

  • If a calculated attribute is to be modified, a set function must be written to respond to the modification, and the set must cause the data on which the calculation depends to change.

  • If the calculated property is determined not to be modified, you can use the abbreviation of the calculated property

Code examples

<body>
    <div id="root">
    
        <input type="text" v-model="firstName"> <br/><br/>
        <input type="text" v-model="lastName" > <br/><br/>
        <h1>{
   
   {name}}</h1>
    </div>
   <script>
    Vue.config.productionTip = false
       const vm = new Vue({
            el:'#root',
            data:{
                firstName:'即兴',
                lastName:'小索奇'
            },
            computed:{
                name:{
                    get(){
       return this.firstName + '-' + this.lastName
                  
                    set(value){
                        console.log(VM)
                        const arr = value.split('-')
                        this.firstName = arr[0]
                        this.lastName = arr[1]
                    }
                }
            }
        })
   </script>
</body>

image-20230819013138164

image-20230819013138164

<body>
    <div id="root">
    
            <input type="text" v-model="firstName"> <br/><br/>
         <input type="text" v-model="lastName"> <br/><br/>
            <h1>{
   
   {name}}</h1>
    </div>
   <script>
    Vue.config.productionTip = false
       const vm = new Vue({
            el:'#root',
            data:{
                firstName:'即兴',
                lastName:'小索奇'
            },
            computed:{
                name:{
                    get(){
                        return this.firstName + '-' + this.lastName
                    },
                    set(value){
                        // console.log(VM)
                        const arr = value.split('-')
                        this.firstName = arr[0]
                        this.lastName = arr [1]
                    }
                }
            }
        })
   </script>
</body>

Computed property abbreviation

  • In actual application, calculated attributes are generally only read and displayed, not modified.

  • When you are sure that it will only be read and not changed, then you can use the abbreviated function

Execution process: After executing the name function, put the name attribute on the VM. Its value is the result returned by the function.

 computed:{
          name(){
             console.log('简写形式,等同于get ')
             return this.firstName + '-' + this.lastName
           }, 
         }

nameYou can use it without adding parentheses when callingname()-> x

expand

You can also use method calls, so why not use it? Look at the following example

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script type="text/JS" src="./js/vue.js"></script>
</head>
<body>
    <div id="root">
    
        <input type="text" v-bind:value="firstName"> <br><br>
        <input type="text" :value="lastName" ><br><br>
        <button> 
            <h1>{
   
   {name()}}</h1>
        </button>
    </div>
   <script>
    Vue.config.productionTip = false
        new Vue({
            el:'#root',
            data:{
                firstName:'即兴',
                lastName:'小索奇'
            },
            methods:{
                name(){
                    return this.firstName + this.lastName
                }
                
            }
        })
   </script>
</body>
</html>

Why not?

Because the update frequency is extremely high, every time the value is changed, the method will be called again to parse the template; it is inefficient.

Listening properties

  • Listening properties are called monitoring properties and the same goes for

In Vue.js, listening properties are usually implemented through "watchers". Monitors allow you to listen to a specific data property in a Vue instance, and then execute corresponding logic when the property value changes. This can Used to perform asynchronous operations, update other data, or trigger other behaviors when properties change.

When the monitored property changes, the callback function is automatically called

There are two ways to define listening attributes: declarative and programmatic. The following explains these two methods and how to use listening attributes in detail:

1. Listening properties:

Use watchoptions to configure one or more listening properties. Each listening property corresponds to a property name and a processing function. When this property changes, the processing function will be triggered.

<body>
  <div id="root">
    <h2>今天天气很{
   
   { info }}</h2>
    <button @click="changeWeather">切换天气</button>
  </div>
</body>

<script type="text/JS">
  Vue.config.productionTip = false;

  const vm = new Vue({
    el: '#root',
    data: {
      isHot: true,
    },
    computed: {
      info() {
        return this.isHot ? '炎热' : '凉爽';
      },
    },
    methods: {
      changeWeather() {
        this.isHot = !this.isHot;
      },
    },
  });
  watch:{
  isHot:{
   immediate:true, 
   handler(newValue,oldValue){
   console.log('isHot被修改了',newValue,oldValue)
    }
   }
  } 
</script>

2. Listening properties:

You can also programmatically$watch set the listening properties in the Vue instance through methods and call VM methods.$watch

  vm.$watch('isHot', {
  // 初始化立即执行handler
    immediate: true,
    // 同理,都能接受新旧值进行处理
    handler(newValue, oldValue) {
      console.log('isHot被修改了', newValue, oldValue);
    },
  });

Whether it is a declarative or programmatic listening attribute, you can perform any operation you need in the processing function of the listening attribute, such as initiating network requests, updating other data attributes, triggering methods, etc.

It should be noted that although listening properties are a powerful tool, too many listening properties may cause the code to become complex and difficult to maintain. In some cases, you can use computed properties (Computed Properties) to replace listening properties. , to improve code readability and performance

You can use watchoptions or $watchmethods to set listening properties to trigger the handler when the property changes.

deep surveillance

A simple summary is that deep monitoring refers to observing and monitoring all nested properties of an object.

  1. Usage: In watchthe options, set thedeep: true

  2. How it works: When set to deep: true, Vue will recursively traverse all sub-properties of the object to ensure that no matter how any nested properties of the object are modified, the callback function will be triggered.

  3. Note: Because deep monitoring needs to recursively monitor all sub-properties of the object, it may have an impact on performance, especially when the object structure is complex and deeply nested.

  4. Usage scenario: Use deep monitoring when you need to respond to changes in the internal properties of the object, not just changes in the reference of the object itself.

a small case

   <body>
  <div id="root">
   <h2>今天天气很{
   
   {info}}</h2>
   <button @click="changeWeather">切换天气</button>
   <hr/>
   <h3>a的值是:{
   
   {numbers.a}}</h3>
   <button @click="numbers.a++">点我让a+1</button>
   <h3>b的值是:{
   
   {numbers.b}}</h3>
   <button @click="numbers.b++">点我让b+1</button>
   <button @click="numbers = {a:666,b:888}">改变numbers对象</button>
   {
   
   {numbers.c.d.e}}
  </div>
 </body>

 <script type="text/JS">
  Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示
  
  const vm = new Vue({
   el:'#root',
   data:{
    isHot:true,
    numbers:{
     a:1,
     b:1,
     c:{
      d:{
       e:100
      }
     }
    }
   },
   computed:{
    info(){
     return this.isHot ? '炎热' : '凉爽'
    }
   },
   methods: {
    changeWeather(){
     this.isHot = !this.isHot
    }
   },
   watch:{
    isHot:{
     handler(newValue,oldValue){
      console.log('isHot被修改了',newValue,oldValue)
     }
    },
    //监视多级结构中某个属性的变化
    /* 'numbers.a':{
     handler(){
      console.log('a被改变了')
     }
    } */
    //监视多级结构中所有属性的变化
    numbers:{
     deep:true,
     handler(){
      console.log('numbers改变了')
     }
    }
   }
  })

 </script>
</html>

Note: When numbers are completely replaced, there is no d. Open the debugging page, so after clicking complete replacement, d will report an error.

deep:trueIf this item is not turned on, when the items in numbers (such as a, b change) the number will not change. When we turn it on, it means monitoring the changes of attributes in the multi-level structure.

Listening attribute abbreviation

  • It can be abbreviated when there is only one in the configuration item handler. If other configurations are required (such as deep), it cannot be abbreviated (usually this can be written by default)

watch: {
  isHot(newValue, oldValue) {
    console.log('isHot被修改了', newValue, oldValue)  
  }
}

Use VM method call

//正常写法
  /* vm.$watch('isHot',{
   immediate:true, //初始化时让handler调用一下
   deep:true,//深度监视
   handler(newValue,oldValue){
    console.log('isHot被修改了',newValue,oldValue)
   }
  }) */

  //简写
  /* vm.$watch('isHot',(newValue,oldValue)=>{
   console.log('isHot被修改了',newValue,oldValue,this)
  }) */

Compare listener properties & computed properties

Computed properties mainly apply to:

  • Data needs to be converted or formatted before displaying

  • It is necessary to use multiple data to calculate a result and display it.

  • The results need to be cached to avoid repeated calculations each time

  • Floating panels or lists require repeated calculations for each element

Listening attributes mainly apply to:

  • Side effects need to be triggered when data changes, such as calling interfaces, navigation routes, etc. (will be mentioned later)

  • Asynchronous operations or expensive processing are required (such as using timers)

  • Need to parameterize or reuse monitoring logic

  • When a change in value requires changing multiple states

Simply put, if you are simply displaying or formatting data, using computed properties can simplify your code and gain performance benefits.

If data changes need to trigger complex logic or side effects, listening properties will be more appropriate.

If a business logic can implement both, the calculated attribute will be given priority.

expand

What does this output of the following code do?

   watch:{
            setTimeout(()=>{
                this.name = this.firstName + '-' + this.lastName
            },1000)
        }

This here points to the Vue instance

Q: If setTimeOutthe head-cutting function is changed to a normal function: setTimeout(function(){}), then where does this point to?

A: Point to window! If the timer is called by the JS engine and the arrow function does not have its own this pointer, it will look outside to find the VM.

Specifically, for methods defined by ordinary functions, its this will be bound to the current Vue instance.

tips

  • The functions that computed can complete can also be completed by watch.

  • The functions that watch can complete may not be completed by computed. For example: watch can perform asynchronous operations. The above timer example illustrates this point.

Two important little principles:

  • Functions managed by Vue are best written as ordinary functions, so that this points to the VM or component instance object, which can better call the VM.

  • Functions that are not managed by Vue (timer callback functions, ajax callback functions, etc., Promise callback functions) are best written as arrow functions, so that the direction of this will not be messed up.

Guess you like

Origin blog.csdn.net/m0_64880608/article/details/133166501