メインコンテンツへスキップ

ライフサイクルフック

Svelte 5では、コンポーネントのライフサイクルは作成と破棄の2つの部分のみで構成されます。その間の、特定の状態が更新される時などは、コンポーネント全体とは関係ありません。状態の変化に対応する必要がある部分のみが通知されます。これは、内部的には変更の最小単位が実際にはコンポーネントではなく、コンポーネントの初期化時に設定される(レンダリング)エフェクトであるためです。結果として、「before update」/「after update」フックのようなものは存在しません。

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

「after update」フックはありませんが、UIが更新されるまで続行するにはtickを使用できます。tickは、保留中の状態変更がすべて適用された後、またはそれがなければ次のマイクロタスクで解決される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でシム化されましたが、Runeを使用するコンポーネント内では使用できません。

<script>
	import { beforeUpdate, afterUpdate } from 'svelte';

	beforeUpdate(() => {
		console.log('the component is about to update');
	});

	afterUpdate(() => {
		console.log('the component just updated');
	});
</script>

beforeUpdateの代わりに$effect.preを使用し、afterUpdateの代わりに$effectを使用してください。これらのRuneはより詳細な制御を提供し、実際に興味のある変更のみに反応します。

チャットウィンドウの例

新しいメッセージが表示されたときに自動的に下にスクロールするチャットウィンドウを実装するには(ただし、すでに下にスクロールしていた場合のみ)、更新する前にDOMを測定する必要があります。

Svelte 4では、これはbeforeUpdateを使用して行いますが、これは欠陥のあるアプローチです。関連しているかどうかに関係なく、すべての更新の前に実行されます。以下の例では、誰かがダークモードを切り替えたときにスクロール位置を操作しないように、updatingMessagesのようなチェックを導入する必要があります。

Runeを使用すると、$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でこのページを編集