ライフサイクルフック
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
コンポーネントがアンマウントされる直前に実行されるコールバックをスケジュールします。
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
「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>