iT邦幫忙

2023 iThome 鐵人賽

DAY 21
0
Modern Web

了不起的 Svelte系列 第 21

第 21 天:Svelte 的生命週期函式:`onMount`

  • 分享至 

  • xImage
  •  

第 21 天:Svelte 的生命週期函式:onMount

「今天下午我們自個兒在這邊能做些什麼呢?」黛西激動的說:「明天能做些什麼呢?接下來的三十年又可以做些什麼呢?」
「別自己找自己麻煩,」貝克兒小姐說:「當元件掛載到 DOM 上之後,元件的生命週期會重新來過。」

~節錄自《The Great Svelte:第七章》

第 21 天要講的事

  1. 生命週期函式 onMount 的介紹
  2. onMount 搭配 HTML 元素選取
  3. 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> 了!

https://i.ibb.co/F3c4bDX/21.gif
圖一、運作如常的互動視窗 (Modal)

onMount 搭配 Javascript 時間函式

  另外一個常見的作法是將 Javascript 的時間函式 setIntervalsetTimeout 放進 onMount 當中,避免不再使用的資源繼續占用記憶體。
  Javascript 的 setIntervalsetTimeout 會註冊一個回呼函式 (callback function),並在指定的時間執行這些回呼函式。如果不把 setIntervalsetTimeout 放進 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 紀錄的動作。

https://i.ibb.co/Rjg3753/21.gif
圖二、看我們閃閃爍爍的色票產生器

  今天關於 Svelte 提供的生命週期函式 onMount 的介紹就到這邊了。完整的程式碼可以在 Github 資源庫當中找到。謝謝大家。


上一篇
第 20 天:Svelte 中的邏輯運作:`await` 邏輯區塊
下一篇
第 22 天:Svelte 資料綁定 `bind`
系列文
了不起的 Svelte30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言