生命週期函數
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>
- 效果