跳至主要內容

生命週期鉤子

在 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

排定一個回呼函式,在元件卸載之前立即執行。

onMountbeforeUpdateafterUpdateonDestroy 中,這是唯一一個在伺服器端元件內執行的鉤子。

function onDestroy(fn: () => any): void;

排定一個回呼函式,在元件卸載之前立即執行。

onMountbeforeUpdateafterUpdateonDestroy 中,這是唯一一個在伺服器端元件內執行的鉤子。

<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>

在 GitHub 上編輯此頁面

上一頁 下一頁