What is the difference between watch and watchEffect in Vue3?

Notes for learning vue

1. watch is lazy execution, that is, it will be executed only when the monitored value changes, but watchEffect is different, watchEffect will be executed every time the code is loaded.

Note: (Ignore the configuration of the third parameter of watch, if you modify the configuration item, it can also be executed immediately).

2. Watch needs to pass the monitored object, watchEffect does not.

3. watch can only monitor responsive data: attributes defined by ref and objects defined by reactive. If you directly monitor the attributes in the object defined by reactive, it is not allowed (a warning will be reported), unless you use a function to convert it. In fact, it is said on the official website The listener for a getter.

4. watchEffect does not work if it monitors the object defined by reactive, it can only monitor the properties in the object.

First look at the code of watchEffect and verify it

<template>
<div>
  请输入firstName:
  <input type="text" v-model="firstName">
</div>
<div>
  请输入lastName:
  <input type="text" v-model="lastName">
</div>
<div>
  请输入obj.text:
  <input type="text" v-model="obj.text">
</div>
 <div>
 【obj.text】 {
   
   {obj.text}}
 </div>
</template>
 

The following methods all return with three tags.

<script>
import {ref, reactive, watch, watchEffect} from 'vue'
export default {
  name: "HelloWorld",
  props: {
    msg: String,
  },
  setup(props,content){
    let firstName = ref('')
    let lastName = ref('')
    let obj= reactive({
        text:'hello'
      })
    watchEffect(()=>{
      console.log('触发了watchEffect');
      console.log(`组合后的名称为:${firstName.value} ${lastName.value}`)
    })
    return{
      obj,
      firstName,
      lastName
    }
  }
};
</script>

<script>
import {ref, reactive, watch, watchEffect} from 'vue'
export default {
  name: "HelloWorld",
  props: {
    msg: String,
  },
  setup(props,content){
    let firstName = ref('')
    let lastName = ref('')
    let obj= reactive({
        text:'hello'
      })
    watchEffect(()=>{
      console.log('触发了watchEffect');
      // 这里我们不使用firstName.value/lastName.value ,相当于是监控整个ref,对应第四点上面的结论
      console.log(`组合后的名称为:${firstName} ${lastName}`)
    })
    return{
      obj,
      firstName,
      lastName
    }
  }
};
</script>

<script>
import {ref, reactive, watch, watchEffect} from 'vue'
export default {
  name: "HelloWorld",
  props: {
    msg: String,
  },
  setup(props,content){
    let firstName = ref('')
    let lastName = ref('')
    let obj= reactive({
        text:'hello'
      })
    watchEffect(()=>{
      console.log('触发了watchEffect');
      console.log(obj);
    })
    return{
      obj,
      firstName,
      lastName
    }
  }
};
</script>

<script>
import {ref, reactive, watch, watchEffect} from 'vue'
export default {
  name: "HelloWorld",
  props: {
    msg: String,
  },
  setup(props,content){
    let firstName = ref('')
    let lastName = ref('')
    let obj= reactive({
        text:'hello'
      })
    //watchEffect(()=>{
     // console.log('触发了watchEffect');
     // console.log(obj);
   // })
watchEffect(()=>{
      console.log('触发了watchEffect');
      console.log(obj.text);
    })
    return{
      obj,
      firstName,
      lastName
    }
  }
};
</script>

 Look at the watch code again and verify

<template>
<div>
  请输入firstName:
  <input type="text" v-model="firstName">
</div>
<div>
  请输入lastName:
  <input type="text" v-model="lastName">
</div>
<div>
  请输入obj.text:
  <input type="text" v-model="obj.text">
</div>
 <div>
 【obj.text】 {
   
   {obj.text}}
 </div>
</template>

The following methods are all echoed in these three tags 


<script>
import {ref, reactive, watch, watchEffect} from 'vue'
export default {
  name: "HelloWorld",
  props: {
    msg: String,
  },
  setup(props,content){
    let firstName = ref('')
    let lastName = ref('')
    let obj= reactive({
        text:'hello'
      })
   // watch是惰性执行, 默认初始化之后不会执行,只有值有变化才会触发,可通过配置参数实现默认执行
    watch(obj, (newValue, oldValue) => {
      // 回调函数
      console.log('触发监控更新了new',  newValue);
      console.log('触发监控更新了old',  oldValue);
    })
    return{
      obj,
      firstName,
      lastName
    }
  }
};
</script>

Configure immediate parameters, execute immediately, and monitor deeply

// 配置immediate参数,立即执行,以及深层次监听
 watch(obj, (newValue, oldValue) => {
      // 回调函数
      console.log('触发监控更新了new',  newValue);
      console.log('触发监控更新了old',  oldValue);
    }, {
      immediate: true,
      deep: true
    })

Monitor the entire reactive object. From the above figure, you can see that deep is actually enabled by default, even if we set it to false, it is still invalid. And the old value cannot be obtained.

To get the old value, you need to monitor the properties of the object, that is, monitor a getter, see the figure below

<script>
import { ref, reactive, watch, watchEffect } from "vue";
export default {
  name: "HelloWorld",
  props: {
    msg: String,
  },
  setup(props, content) {
    let firstName = ref("");
    let lastName = ref("");
    let obj = reactive({
      text: "hello",
    });

    //错误写法,会报警告,这不是监听对象的一个get

    // watch(
    //   obj.text,
    //   (newValue, oldValue) => {
    //     // 回调函数
    //     console.log("触发监控更新了new", newValue);
    //     console.log("触发监控更新了old", oldValue);
    //   },
    //   {
    //     immediate: true,
    //     deep: false,
    //   }
    // );

    //正确写法

    watch(
      () => obj.text,
      (newValue, oldValue) => {
        // 回调函数
        console.log("触发监控更新了new", newValue);
        console.log("触发监控更新了old", oldValue);
      },
      {
        immediate: true,
        deep: true,
      }
    );

    return {
      obj,
      firstName,
      lastName,
    };
  },
};
</script>

Summarize:

If reactive data is defined and you want to use watch to monitor data changes, the old value cannot be obtained correctly, and the configuration of the deep attribute is invalid, and deep monitoring is automatically enabled forcibly.

If you use ref to initialize an object or array type of data, it will be automatically converted to a reactive implementation to generate a proxy proxy object. also becomes unable to get the old value correctly

For data generated in any way, if the accepted variable is a proxy proxy object, it will cause the watch object to fail to obtain the old value correctly in the watch callback

So when using watch to monitor the object, if you don't need to use the old value, you can monitor the object normally.

When listening to change the old value that needs to be used in the function, you can only listen to obj.XXX.

If you don't understand, refer to more addresses:  What is the difference between watch and watchEffect in Vue3? _Common Netizen's Blog-CSDN Blog

Guess you like

Origin blog.csdn.net/snow_living/article/details/125599975