onMount
「今天下午我們自個兒在這邊能做些什麼呢?」黛西激動的說:「明天能做些什麼呢?接下來的三十年又可以做些什麼呢?」
「別自己找自己麻煩,」貝克兒小姐說:「當元件掛載到 DOM 上之後,元件的生命週期會重新來過。」~節錄自《The Great Svelte:第七章》
onMount
的介紹onMount
搭配 HTML 元素選取onMount
搭配 Javascript 時間函式 在前端框架中,元件的生命週期是一個重要的概念,每一個元件都有自己的生命週期。當一個元件開始被掛載到文件物件模型 (DOM) 上,元件的生命週期就開始了,一直持續到這個元件從 DOM 當中被卸載為止,即為生命週期結束。往往在實作一個專案的過程中,我們會碰到一些情況,需要在元件生命週期的特定時刻執行特定的工作,這時候就需要用到能夠跟著生命週期一起執行的函式了。而最常被用到的特殊時刻,是元件開始被掛載到 DOM 之後的時刻,也就是元件生命週期的開始。舉例來說,我們可能會需要在元件開始被掛載到 DOM 之後,檢視元件內的 HTML 元素,或是開始計時的動作。因此今天要介紹的,就是 Svelte 所以提供的生命週期函式 onMount
。
onMount
的介紹 生命週期函式 onMount
,顧名思義,就是會在該元件掛載到 DOM 之後會執行的函式。語法很簡單:
<script>
import { onMount } from 'svelte';
onMount(() => {
console.log('這個元件被掛載到 DOM 囉');
});
</script>
第二行:import { onMount } from 'svelte';
我們要先從 'svelte'
當中引入需要使用的函式 onMount
。
第三行:onMount(() => {
直接呼叫 onMount
這個生命週期函式,而 onMount
只接受一個參數,也就是我們想要在元件被掛載之後立刻執行的函式。
第四行:console.log('這個元件被掛載到 DOM 囉');
以上面的例子來說,我們給 onMount
的參數,是一個執行之後會記錄下文字訊息 這個元件被掛載到 DOM 囉
的函式。
這就是 onMount
的用法。除此之外,onMount
可以傳回一個函式,這個函式會在元件被卸載的時候執行。有些時候我們需要在元件被卸載的的時候做一些善後的工作,比如把不再用到的記憶體資源釋放出來之類的,這時候就可以利用 onMount
回傳函式來達成目的。
<script>
import { onMount } from 'svelte';
onMount(() => {
console.log('這個元件被掛載到 DOM 囉');
return () => {
console.log('這個元件從 DOM 當中被卸載下來囉');
};
});
</script>
第五行:return () => {
從 onMount
當中傳回一個函式,這個函式會在元件被卸載時執行。
第六行:console.log('這個元件從 DOM 當中被卸載下來囉');
以這個例子來說,我們讓這個元件被卸載時,執行函式紀錄下這段文字訊息:這個元件從 DOM 當中被卸載下來囉
。
以上就是 onMount
用法的說明。接下來,我們也試試看把 onMount
這個功能放進色票產生器的專案當中吧。
onMount
搭配 HTML 元素選取 還記得第 14 天實作一個互動視窗 (Modal) 的時候,在 Modal.svelte
這個元件當中用了一段看起來很彆扭的程式碼:
/src/lib/Modal.svelte
<script>
import { createEventDispatcher } from "svelte";
export let showModal;
let dialog;
const dispatch = createEventDispatcher();
const handleClose = () => dispatch('closeModal');
setTimeout(() => {
dialog = document.querySelector('dialog');
}, 1);
$: if (dialog && showModal) dialog.showModal();
$: if (dialog && !showModal) dialog.close();
</script>
第九行:setTimeout(() => {
做一個定時器,時間到了自動執行裡面的函式。
第十行:dialog = document.querySelector('dialog');
執行什麼函式呢?原來是 document.querySelector('dialog')
。
第十一行:}, 1);
我們設定 1
毫秒之後執行函式。
為什麼要怎麼做呢?如果不把 document.querySelector('dialog')
設定在 1
毫秒之後執行,會因為元件還沒被掛載完成,HTML 元素還沒出現在 DOM 上面,而找不到我們想找的 <dialog>
。
太棒了,這完全就是使用 onMount
的場合呀。讓我們重新修改一下程式碼:
/src/lib/Modal.svelte
<script>
import { onMount } from "svelte";
import { createEventDispatcher } from "svelte";
export let showModal;
let dialog;
const dispatch = createEventDispatcher();
const handleClose = () => dispatch("closeModal");
onMount(() => {
dialog = document.querySelector("dialog");
});
$: if (dialog && showModal) dialog.showModal();
$: if (dialog && !showModal) dialog.close();
</script>
第二行:import { onMount } from "svelte";
記得要從 "svelte"
當中引入 onMount
。
第十行:onMount(() => {
直接呼叫 onMount
,並傳入一個作為參數的函式。這個函式會被安排在元件掛載進 DOM 之後執行。
第十一行:dialog = document.querySelector("dialog");
要在元件被掛載到 DOM 之後執行的函式就是這一段。因為元件已經掛載進 DOM,執行 document.querySelector("dialog")
就不怕找不到 <dialog>
了!
圖一、運作如常的互動視窗 (Modal)
onMount
搭配 Javascript 時間函式 另外一個常見的作法是將 Javascript 的時間函式 setInterval
跟 setTimeout
放進 onMount
當中,避免不再使用的資源繼續占用記憶體。
Javascript 的 setInterval
跟 setTimeout
會註冊一個回呼函式 (callback function),並在指定的時間執行這些回呼函式。如果不把 setInterval
跟 setTimeout
放進 onMount
,那麼每當元件走完一個生命週期,也就是當元件經過掛載又卸載的動作,就會多註冊一組回呼函式。這些回呼函式已經沒有作用,卻因為被註冊,而且沒有辦法消除,導致記憶體空間的浪費。表現出來的結果是,當我們重複掛載/卸載元件的動作,因為記憶體空間越來越少,瀏覽器執行起來就越來越慢了。
今天就讓我們練習使用 onMount
搭配 setInterval
,讓色票如霓虹燈般閃爍吧:
/src/App.svelte
<!-- 在 Javascript 當中 import Counter、Modal、Palettes -->
<script>
import { onMount } from "svelte";
import Counter from "./lib/Counter.svelte";
import Modal from "./lib/Modal.svelte";
import Palettes from "./lib/Palettes.svelte";
/* 忽略中間的段落 */
onMount(() => {
const intervalId = setInterval(() => {
palettes = palettes.map((palette) => ({
...palette,
hex: generateHex(),
}));
}, 2000);
return () => clearInterval(intervalId);
});
</script>
因為我們的 App.svelte
已經越寫越長了,讓我們忽略與今天內容不相關的程式碼,專注在 onMount
的部分。
第三行:import { onMount } from "svelte";
記得引入需要用的 onMount
。
第十行:onMount(() => {
直接呼叫 onMount
,並傳入一個作為參數的函式。這個函式會被安排在元件掛載進 DOM 之後執行。
第十一行:const intervalId = setInterval(() => {
這個函式要執行的內容就是用 setInterval
做一個定時器,每 2000
毫秒改變 palettes
內代表色票 Hex 色碼的數值,讓我們的色票每 2000
毫秒改變一次顏色。記得將 setInterval
回傳的識別碼用 intervalId
記錄下來。
第十八行:return () => clearInterval(intervalId);
最後利用 onMount
回傳一個函式。這個函式會在該元件被卸載的時候執行。因為我們希望元件被卸載的時候,用來記憶 setInterval
的記憶體空間可以釋放出來,所以藉由回傳 () => clearInterval(intervalId)
來達到元件卸載時順便清掉 setInterval
紀錄的動作。
圖二、看我們閃閃爍爍的色票產生器
今天關於 Svelte 提供的生命週期函式 onMount
的介紹就到這邊了。完整的程式碼可以在 Github 資源庫當中找到。謝謝大家。