生命週期鉤子
在 Svelte 5 中,元件生命週期僅包含兩個部分:它的建立和它的銷毀。介於兩者之間的一切 — 當某些狀態更新時 — 與整個元件無關;僅會通知需要對狀態變更做出反應的部分。這是因為在底層,最小的變更單位實際上不是元件,而是元件在初始化時設定的(渲染)效果。因此,沒有所謂的「更新前」/「更新後」鉤子。
onMount
onMount
函式會排定一個回呼函式,在元件掛載到 DOM 後立即執行。它必須在元件初始化期間呼叫(但不一定要在元件內部;可以從外部模組呼叫)。
onMount
不會在伺服器上渲染的元件內執行。
<script>
import { onMount } from 'svelte';
onMount(() => {
console.log('the component has mounted');
});
</script>
如果從 onMount
返回一個函式,則會在元件卸載時呼叫它。
<script>
import { onMount } from 'svelte';
onMount(() => {
const interval = setInterval(() => {
console.log('beep');
}, 1000);
return () => clearInterval(interval);
});
</script>
只有當傳遞給
onMount
的函式同步返回一個值時,此行為才會有效。async
函式始終返回一個Promise
,因此無法同步返回一個函式。
onDestroy
排定一個回呼函式,在元件卸載之前立即執行。
在 onMount
、beforeUpdate
、afterUpdate
和 onDestroy
中,這是唯一一個在伺服器端元件內執行的鉤子。
function onDestroy(fn: () => any): void;
排定一個回呼函式,在元件卸載之前立即執行。
在 onMount
、beforeUpdate
、afterUpdate
和 onDestroy
中,這是唯一一個在伺服器端元件內執行的鉤子。
<script>
import { onDestroy } from 'svelte';
onDestroy(() => {
console.log('the component is being destroyed');
});
</script>
tick
雖然沒有「更新後」鉤子,但您可以使用 tick
來確保在繼續之前 UI 已更新。tick
返回一個 Promise,該 Promise 在任何待處理的狀態變更都已應用後解析,或者如果沒有,則在下一個微任務中解析。
<script>
import { tick } from 'svelte';
$effect.pre(() => {
console.log('the component is about to update');
tick().then(() => {
console.log('the component just updated');
});
});
</script>
已棄用:beforeUpdate / afterUpdate
Svelte 4 包含在整個元件更新之前和之後運行的鉤子。為了向後相容,這些鉤子在 Svelte 5 中被墊片化,但在使用符文的元件內部不可用。
<script>
import { beforeUpdate, afterUpdate } from 'svelte';
beforeUpdate(() => {
console.log('the component is about to update');
});
afterUpdate(() => {
console.log('the component just updated');
});
</script>
請改用 $effect.pre
來取代 beforeUpdate
,並使用 $effect
來取代 afterUpdate
- 這些符文提供更精細的控制,並且只對您實際感興趣的變更做出反應。
聊天視窗範例
若要實作一個在出現新訊息時自動捲動到底部的聊天視窗(但只有在您已經捲動到底部時),我們需要在更新 DOM 之前測量它。
在 Svelte 4 中,我們使用 beforeUpdate
來執行此操作,但這是一個有缺陷的方法 — 它會在每次更新之前觸發,無論它是否相關。在下面的範例中,我們需要引入像 updatingMessages
這樣的檢查,以確保在有人切換深色模式時,我們不會弄亂捲動位置。
使用符文,我們可以使用 $effect.pre
,它的行為與 $effect
相同,但在 DOM 更新之前執行。只要我們在效果主體中明確引用 messages
,它就會在 messages
變更時執行,而不會在 theme
變更時執行。
因此,beforeUpdate
及其同樣麻煩的對應項 afterUpdate
在 Svelte 5 中已被棄用。
<script>
import { beforeUpdate, afterUpdate, tick } from 'svelte';
let updatingMessages = false;
let theme = $state('dark');
let messages = $state([]);
let viewport;
beforeUpdate(() => {
$effect.pre(() => {
if (!updatingMessages) return;
messages;
const autoscroll = viewport && viewport.offsetHeight + viewport.scrollTop > viewport.scrollHeight - 50;
if (autoscroll) {
tick().then(() => {
viewport.scrollTo(0, viewport.scrollHeight);
});
}
updatingMessages = false;
});
function handleKeydown(event) {
if (event.key === 'Enter') {
const text = event.target.value;
if (!text) return;
updatingMessages = true;
messages = [...messages, text];
event.target.value = '';
}
}
function toggle() {
toggleValue = !toggleValue;
}
</script>
<div class:dark={theme === 'dark'}>
<div bind:this={viewport}>
{#each messages as message}
<p>{message}</p>
{/each}
</div>
<input onkeydown={handleKeydown} />
<button onclick={toggle}> Toggle dark mode </button>
</div>