2024-06-05|閱讀時間 ‧ 約 25 分鐘

小心遺漏的 watch 讓網頁爆炸!Σ(ˊДˋ;)

raw-image


最近注意到 watch 有一個有趣的現象,一個可能會挖坑的現象。(´,,•ω•,,)


在某些情境下,watch 的位置可能不會在元件最外層。


類似這種感覺:

<script setup>
import { ref, watch} from 'vue'

const data = ref(1);

setTimeout(() => {
watch(data, (value) => {
console.log('[ Comp ] data: ', value);
})
}, 500);
</script>

先別吐槽這樣寫超廢,只是個簡單的示意啦。¯\( ͡° ͜ʖ ͡°)


(其實如果有這類需求,推薦使用 VueUse 提供的 watchPausable、watchTriggerable 這類進階版 watch,看起來更漂亮、更好維護。)


一般我們知道,元件 onUnmounted 後,watch 就會自動解除。


但是如果是剛剛的那個例子,onUnmounted 後 watch 不會自動解除喲!ლ(╹◡╹ლ)


所以如果頁面中有很多這類 watch,很有可能讓網頁爆掉唷!o(≧∀≦)o


路人:「是在開心個毛線喔。(゚Д゚*)ノ」


這是因為如果在內層呼叫 watch,會讓 watch 與元件處在不同 effectScope,導致此結果。


解法也很簡單,勤奮一點手動解除。◝( •ω• )◟

<script setup>
import { ref, watch } from 'vue'

const data = ref(1);

let unwatch;
setTimeout(() => {
unwatch = watch(data, (value) => {
console.log('[ CompUnwatch ] data: ', value);
})
}, 500);

onUnmounted(() => {
console.log('[ onUnmounted ]');
unwatch();
})
</script>

路人:「啊如果有很多 watch,這樣一個一個解除很累欸。Σ(ˊДˋ;)」


鱈魚:「…('◉◞⊖◟◉` ),先不探究這種 code 怎麼過得了 code review ,假設真的有很多 watch 要解除,可以用剛剛提到的關鍵字『effectScope』」


effectScope 可以用來捕捉範圍內的 reactive effects,所以可以把所有的 watch 收集起來統一解除。


例如像這樣:

<script setup>
import { ref, watch, onUnmounted, effectScope } from 'vue'

const scope = effectScope()
const data = ref(1);
const number = ref(0);

setTimeout(() => {
scope.run(() => {
watch(data, (value) => {
console.log('[ CompScope ] data: ', value);
})
})
}, 500);

setTimeout(() => {
scope.run(() => {
watch(number, (value) => {
console.log('[ CompScope ] number: ', value);
})
})
}, 1000);

onUnmounted(() => {
console.log('[ onUnmounted ]');
scope.stop();
})
</script>

世界再度回復和平!✧*。٩(ˊᗜˋ*)و✧*。


以上提到的範例可以在此連結查看

(可以觀察到即使元件消失後,devtool 的 console 依舊持續跑出 log)


不過說的真,請不要這樣用 watch。…(›´ω`‹ )

分享至
成為作者繼續創作的動力吧!
與 Vue 一同打滾的點點滴滴
從 Google News 追蹤更多 vocus 的最新精選內容從 Google News 追蹤更多 vocus 的最新精選內容

發表回應

成為會員 後即可發表留言
© 2024 vocus All rights reserved.