Svelte學習筆記七:組件的生命週期

生命週期函數

svelte存在的聲明週期包括

  • onMount
  • onDestory
  • beforeUpdate
  • afterUpdate
  • tick(暫時沒有找到相關的例子)

1. onMount

翻譯自官網文檔:onMount函數在組件都掛在在DOM上之後會觸發,在組件初始化的過程中進行調用。如果onMount返回了一個函數, 則這個函數會在組件卸載的時候觸發。類似react中的USeEffect,我是這麼理解的。

但是在實際測試過程中,當我的onMount返回一個函數,好像在組件卸載的時候並不會被執行

一般對於一些列表組件,我們希望在列表初始化的時候,拉取數據,我們可以在onMount中寫這個東西

  import { onMount } from "svelte";
  
  onMount(async () => {
    console.log('Mounted')
    loading = true;
    const res = await fetch("http://localhost:3000/students");
    const data = await res.json()

    loading = true;
    students = data.data;

    return () => console.log("unMounted")
  });

2. onDestory

翻譯自官方文檔: 在組件卸載時調用的回調。

應用場景,當我們頁面加載的時候,我們可能開啓一些定時任務,比如使用setInterval,如果當頁面卸載時,不關閉該setInterval會產生內存泄漏的問題。因此,onDestory就是給了這麼一個回調。

import { onDestroy } from "svelte";

onDestroy(() => clearInterval(timer1));

3. beforeUpdate和afterUpdate

翻譯自官方文檔:beforeUpdate執行該回調函數在組件狀態改變但組件更新之前,但第一次被調用的時候在onMounted之前;afterUpdate在組件被更新之後調用。

我的理解就是:此時props和state在beforeUpdate和afterUpdate其實都已經被更新,但是還沒有渲染到dom上。因此,我們去拿對應的state,應該都是更新過後的state了

因此我們來解決一個問題:如果需要對prevState和curState進行對比的操作。

<script>
  import { beforeUpdate, afterUpdate } from "svelte";
  
  export let count;
  let lastCount;

  beforeUpdate(() => {
      console.log(`before update = ${count}, lastCount=${lastCount}`);
  })

  afterUpdate(() => (lastCount = count ,console.log(`after update = ${count}`)));
  
</script>

上述代碼中,count是一個prop,其受外部控制,來模擬數據更新的場景。

我們可以通過一個已有變量lastCount,在afterUpdate的時候將其值進行更新,這樣beforeUpdate中就可以獲取原來的state,從而做出相應的操作了。

4. tick

tick的作用類似於vue中的nextTick,都是等到下一次更新的時候進行後續的一些操作。不過區別是,svelte中的tick是一個Promise封裝的異步函數。我們可以通過await tick(),使後續的代碼“停下”,等到下一次頁面更新的時候,再調用後續的操作。這裏暫時沒想到好的例子。如果有好的場景需要用到這個的話,可以評論一下,我去實現一下。來看一個官方的例子。

<script>
	import { tick } from 'svelte';

	let text = `Select some text and hit the tab key to toggle uppercase`;

	async function handleKeydown(event) {
		if (event.key !== 'Tab') return;

		event.preventDefault();

		const { selectionStart, selectionEnd, value } = this;
		const selection = value.slice(selectionStart, selectionEnd);

		const replacement = /[a-z]/.test(selection)
			? selection.toUpperCase()
			: selection.toLowerCase();

		text = (
			value.slice(0, selectionStart) +
			replacement +
			value.slice(selectionEnd)
		);

		await tick();
		this.selectionStart = selectionStart;
		this.selectionEnd = selectionEnd;
	}
</script>

<style>
	textarea {
		width: 100%;
		height: 200px;
	}
</style>

<textarea value={text} on:keydown={handleKeydown}></textarea>

這個例子是因爲,需要在tab操作之後還是讓選中的單詞處於被選中的狀態。因此在tick更新之後,將textArea的Selection設爲對應單詞的start和end,讓其還是被選中的狀態

5. 生命週期的整體代碼

<!-- LifeCycle.svelte -->
<script>
  import { onMount, onDestroy, beforeUpdate, afterUpdate } from "svelte";
  
  export let count;
  let students = [];
  let loading = false;
  let lastCount;

  onMount(async () => {
    console.log('Mounted')
    loading = true;
    const res = await fetch("http://localhost:3000/students");
    const data = await res.json()

    loading = true;
    students = data.data;

    return () => console.log("unMounted")
  });

  onDestroy(() => console.log("is Destory"));
  

  beforeUpdate(() => {
      console.log(`before update = ${count}, lastCount=${lastCount}`);
  })

  afterUpdate(() => (lastCount = count ,console.log(`after update = ${count}`)));


</script>

<style>
  .students {
    padding: 20px;
    border: 1px solid #333;
    border-radius: 8px;
  }
</style>

<div class="students">

  {count}

  {#if !loading}
    <!-- content here -->
    正在加載學生信息
  {:else}
    <!-- else content here -->
    {#if !students.length}
      <!-- content here -->
      沒有學生信息了TAT
    {:else}
      <!-- else content here -->
      <table>
        <thead>
          <th>姓名</th>
          <th>年齡</th>
        </thead>
      </table>

      <tbody>

        {#each students as stu}
          <!-- content here -->
          <tr>
            <td>{stu.name}</td>
            <td>{stu.age}</td>
          </tr>
        {/each}

      </tbody>
    {/if}
  {/if}

</div>

<!-- App.svelte -->
<script>
  import LifeCycle from "./LifeCycle.svelte";

  let isShow = false;
  let count = 0;

  let handleShow = () => (isShow = !isShow);
  
  function addCount() {
	  count++;
  }
</script>
<div>
  {#if isShow}
    <!-- content here -->
    <LifeCycle count={count} />
  {:else}
    <!-- else content here -->
    組件被卸載
  {/if}

  <button on:click={handleShow}>
	{#if isShow}
		 <!-- content here -->
		 卸載組件
	{:else}
		 <!-- else content here -->
		 添加組件
	{/if}
  </button>

  <button on:click={addCount}>+1</button>
</div>
  • 效果

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章