vue3中 watch、watchEffect區(qū)別

通過官網(wǎng)上的介紹得出如下簡單的結論

1、watch是惰性執(zhí)行,也就是只有監(jiān)聽的值發(fā)生變化的時候才會執(zhí)行,但是watchEffect不同,每次代碼加載watchEffect都會執(zhí)行(忽略watch第三個參數(shù)的配置,如果修改配置項也可以實現(xiàn)立即執(zhí)行)
2、watch需要傳遞監(jiān)聽的對象,watchEffect不需要
3、watch只能監(jiān)聽響應式數(shù)據(jù):ref定義的屬性和reactive定義的對象,如果直接監(jiān)聽reactive定義對象中的屬性是不允許的(會報警告),除非使用函數(shù)轉換一下。其實就是官網(wǎng)上說的監(jiān)聽一個getter
4、watchEffect如果監(jiān)聽reactive定義的對象是不起作用的,只能監(jiān)聽對象中的屬性。

先看一下watchEffect的代碼,驗證一下
<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>

<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('觸發(fā)了watchEffect');
      console.log(`組合后的名稱為:${firstName.value} ${lastName.value}`)
    })
    return{
      obj,
      firstName,
      lastName
    }
  }
};
</script>

看下圖可以看到。
image.png

image.png

改造一下代碼

<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>

<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('觸發(fā)了watchEffect');
      // 這里我們不使用firstName.value/lastName.value ,相當于是監(jiān)控整個ref,對應第四點上面的結論
      console.log(`組合后的名稱為:${firstName} ${lastName}`)
    })
    return{
      obj,
      firstName,
      lastName
    }
  }
};
</script>

image.png
<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>

<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('觸發(fā)了watchEffect');
      console.log(obj);
    })
    return{
      obj,
      firstName,
      lastName
    }
  }
};
</script>

image.png

稍微改造一下

watchEffect(()=>{
      console.log('觸發(fā)了watchEffect');
      console.log(obj.text);
    })
image.png
再看一下watch的代碼,驗證一下
<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>

<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是惰性執(zhí)行, 默認初始化之后不會執(zhí)行,只有值有變化才會觸發(fā),可通過配置參數(shù)實現(xiàn)默認執(zhí)行
    watch(obj, (newValue, oldValue) => {
      // 回調函數(shù)
      console.log('觸發(fā)監(jiān)控更新了new',  newValue);
      console.log('觸發(fā)監(jiān)控更新了old',  oldValue);
    })
    return{
      obj,
      firstName,
      lastName
    }
  }
};
</script>

配置immediate參數(shù),立即執(zhí)行,以及深層次監(jiān)聽

// 配置immediate參數(shù),立即執(zhí)行,以及深層次監(jiān)聽
 watch(obj, (newValue, oldValue) => {
      // 回調函數(shù)
      console.log('觸發(fā)監(jiān)控更新了new',  newValue);
      console.log('觸發(fā)監(jiān)控更新了old',  oldValue);
    }, {
      immediate: true,
      deep: true
    })
image.png
監(jiān)控整個reactive對象,從上面的圖可以看到 deep 實際默認是開啟的,就算我們設置為false也還是無效。而且舊值獲取不到。

要獲取舊值則需要監(jiān)控對象的屬性,也就是監(jiān)聽一個getter,看下圖


image.png

正確的寫法,運行之后看下圖


image.png

總結:

  • 如果定義了reactive的數(shù)據(jù),想去使用watch監(jiān)聽數(shù)據(jù)改變,則無法正確獲取舊值,并且deep屬性配置無效,自動強制開啟了深層次監(jiān)聽。
  • 如果使用 ref 初始化一個對象或者數(shù)組類型的數(shù)據(jù),會被自動轉成reactive的實現(xiàn)方式,生成proxy代理對象。也會變得無法正確取舊值。
  • 用任何方式生成的數(shù)據(jù),如果接收的變量是一個proxy代理對象,就都會導致watch這個對象時,watch回調里無法正確獲取舊值。

所以當大家使用watch監(jiān)聽對象時,如果在不需要使用舊值的情況,可以正常監(jiān)聽對象沒關系;但是如果當監(jiān)聽改變函數(shù)里面需要用到舊值時,只能監(jiān)聽 對象.xxx屬性 的方式才行。

詳細說明請移步這里大佬們說的非常好 點擊傳送門

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容