Vue 監聽器和計算屬性到底有什麼不同?
各自的適用場景
計算屬性臨時快照
官方文檔對於計算屬性提到了一個重要的點子——「臨時快照」(可能就是前面說的計算屬性緩存),每當源狀態發生變化時,就會創建一個新的快照。
有時候創建快照是沒有意義的,對於間隔時間很短的源數據修改,比如輸入框輸入時頁面上的一些變化。輸入第一個字符到第二個字符之間的間隔時間,字符有長有短,每一次都要創建「臨時快照」,這樣是沒有意義的,反而可能增加開銷。
計算屬性除了可以用於複雜的模板取值計算(普通函數也可以做,也不是它的特性),還可以計算一次而在頁面上多次使用(這是計算屬性的「臨時快照」的優勢)。
監聽器的副作用
因此,上面說到的情況就更加適合用監聽器來做,監聽器不創建「臨時快照」。監聽器更適用於官方文檔說的場景:「我們需要在狀態變化時執行一些『副作用』:例如更改 DOM,或是根據異步操作的結果去修改另一處的狀態」。
監聽器的副作用就是被監測的數據源發生變化才被觸發,而不能被其他數據源發生變化而受到影響。具體往下看,就是我說的監聽器單一性。
深入思考兩者區別
計算屬性由於在計算過程中依賴了很多響應式數據,一旦某一個響應式數據發生變化,那麼整個計算屬性都將重新計算。我就自以為計算屬性有共享性。
雖然監聽器也可以依賴於很多響應式數據,但是監聽器只負責一個數據源,而被依賴的其他響應式數據一旦發生變化,都無法觸發這個監聽器,即監聽器的單一性。
監聽器:單一性
Talk is cheap. Show me the code.
定義兩個輸入框需要綁定的響應式數據 input、copyInput,監聽器只負責監聽 input,當監聽器被觸發時,新的值將賦值給 input,並且 input 也拼接給 copyInput(這裡為了讓兩個產生聯繫而設計的無腦代碼):
let input = ref("");
let copyInput = ref("");
watch(input, (newVal, oldVal) => {
input.value = newVal;
copyInput.value += input.value;
console.log("input value has changed.");
});
輸入框綁定響應式數據,頁面展示 copyInput:
<div class="demo1">
<div>CopyInput Value: {{ copyInput }}</div>
<div>
<span>Input: </span>
<input v-model="input" />
</div>
<div>
<span>CopyInput: </span>
<input v-model="copyInput" />
</div>
</div>
第一個輸入框內(即綁定 input 的輸入框)輸入三次,監聽器被觸發 3 次,當第二個輸入框的數據發生變化時,控制台不打印,也就是說,監聽器裏面被依賴的數據沒有因為改變而被觸發。
計算屬性:共享性
計算屬性裏面被依賴的其中一個響應式數據發生了變化,整個計算屬性都將被重新計算。那麼,計算屬性是否和上面提到的監聽器一樣呢?
let input = ref("");
let copyInput = ref("");
const result = computed(() => {
console.log("computed has changed.");
return (copyInput.value += input.value);
});
<div class="demo2">
<div>CopyInput Value Result: {{ result }}</div>
<div>
<span>Input: </span>
<input v-model="input" />
</div>
<div>
<span>CopyInput: </span>
<input v-model="copyInput" />
</div>
</div>
不管我改哪一個,只要是被計算屬性依賴的數據源發生改變,這個計算屬性都被觸發,即共享性:
總結
(1)計算屬性適合數據源發生變化間隔長,且頁面使用它的次數多的情況;監聽器適合數據源發生變化間隔短,或有異步操作,或有副作用的情況。
(2)如果不想其他響應式數據發生變化而導致被監測的源數據發生變化,那麼就使用監聽器。如果其他響應式數據發生變化,而被監測的源數據也一同發生變化,那麼就使用計算屬性。
聲明
文章中所說的計算屬性具有共享性和監聽器具有單一性是為了方便理解他們之間的不同,博主擅自給的定義,可能存在不嚴謹的地方。
- 計算屬性具有共享性:指的是計算屬性裏面的被依賴的響應式數據只要有一個發生變化,整一個計算屬性都重新計算,牽一髮而動全身。
- 監聽器具有單一性:指的是監聽器只負責它監聽的那個數據源,如果發生變化,才會被觸發,如果裏面被依賴的其他數據源發生變化時,這個監聽器不會被觸發。
以上證明了我所闡述的觀點,如果你有收貨,請給我點個贊+收藏吧👍👍👍!