這是〈Svelte 從小白到入門〉系列的第五集,各集連結如下:


本週末是台灣國慶連假,封面圖特別改用今年國慶的視覺主題「金陽雙十」的編織圖案,祝台灣生日快樂,也感謝這個自由的國度讓我們擁有免於被囚禁在網路長城內的自由。

生命週期

所謂的生命週期,指的是一個 Svelte 元件從被創建到被銷毀之間的幾個關鍵時機點,其中的 onMount 的時機點為元件被瀏覽器 render 出來後的那一刻。

onMount

上一集的 canvas 範例裡,有出現過 onMount() 的函式,當時我們做的是把 <canvas> 元素綁定到 JS 的 canvas 變數上,並利用 Canvas API 撰寫它的一些動態效果,因為必須調用到瀏覽器提供的 Canvas API,就必然得等到 <canvas> 被瀏覽器 render 後才能正確調用,又或者是某些行為必許操作元件內的其他元素,也必須等待瀏覽器把元件都 render 後才可以操作,因此我們才把那些動態效果的敘述放在 onMount() 裡面。

下面的這個例子,我們在 onMount() 裡面用 fetch() 去抓外部 API 的用戶頭像,並顯示出來:

onMount() 內的程式碼,不會在 SSR 階段被執行,而像 fetch() 這個通常用於抓取動態內容的函式也不適合在 SSR 執行,因此放在 onMount() 內也算是適得其所。

另外注意到,在第二集曾經提過的 {#each} 迴圈也可以用 {:else},當 photos 陣列還未生成時,可以用 {:else} 顯示佔位圖或提示文字。

onDestroy

onMount 會在 Svelte 元件在瀏覽器被 render 時執行,onDestroy 則是會在元件被銷毀時執行。

在下面的例子裡,父元件 App 有一個 Timer 子元件,以及一個能切換 Timer 存在與否的按鈕。

Timer 是個以 setInterval() 函式建構的計時器,透過 App 給 Timer 的 callback 函式 handleTick,計時器會把 App 的累積秒數 seconds 持續隨讀秒的頻率加一加一加一,而一旦用戶按下「Close Timer」,App 內的 Timer 元件隨之銷毀,並觸發 Timer 內的 onDestroy(),其內的 clearInterval() 被執行,令原本的 timer 失效。

看文字敘述好像很複雜,實際上真的很複雜…:

beforeUpdate & afterUpdate

元件被更新的前後,也有相對應的生命週期函式可以調用。

顧名思義,beforeUpdate 會在元件更新前調用、afterUpdate 則會在元件更新後調用。

下面這個對話範例,我們希望隨著對話的增加,畫面自動幫用戶捲動到最下方:

範例中,往來的對話內容都放在 JS 的 comments,當用戶送出文字後,對話框綁定的 handleKeydown() 負責更新 comments 的內容,此時就會觸發 beforeUpdate()afterUpdate()beforeUpdate() 用於判斷是否要自動捲動到最底,如果要捲動,則令 autoscrolltrue,而 afterUpdate() 的內容就相當單純了,呼叫 scrollTo() 捲動到最下面。

要特別注意的是,元件在初始化時,onMount 之前,也會觸發 beforeUpdate,因此我們在 beforeUpdate() 函式內有著 autoscroll = div 的敘述,這裡的「div」變數會是 undefined,轉換成 boolean 會是 false,也就是 autoscroll = false,直到瀏覽器把元件 render 後,JS 的 div 才會與 HTML 中的 div.scrollable 綁定,綁定後的 autoscroll 才有可能變為 true

tick

在某些情況下,出於效能的考量,Svelte 並不會立即更新元件狀態,此時我們可以呼叫 tick() 使元件更新狀態。

下面的例子裡,選取一段文字,按下 TAB,選取文字會轉為大寫,在瀏覽器的預設行為下,游標會跳到最末,而我們的程式碼想令游標保持原本選取的區段,因此引入 tick() 令元件更新,並執行保留選取區段的程式碼:

小結

本集重點整理:

  • onMount 發生於 Svelte 元件被瀏覽器 render 之時
  • fetch() 函式一般用於抓取屬於特定用戶的專屬內容,建議放在 onMount() 內執行
  • {#each} 迴圈也可以用 {:else} 用於顯示陣列元素未生成時的內容
  • onDestroy 發生於 Svelte 元件被銷毀之時
  • beforeUpdate 發生於 Svelte 元件更新前
  • afterUpdate 發生於 Svelte 元件更新後
  • tick() 用於令元件更新