
Svelteで親ComponentからのpropsのReactivityを失ってしまうパターン
Posted on 2025/12/15
# Technology
Svelteでは Component や +page.svelte の props を $state(props.count) というようにすると Reactivity が失われてしまいます。
例えば以下のような let count = $state(0); を Count.svelte という Component に渡します。
<!-- +page.svelte -->
<script>
import Count from "./Count.svelte"
let count = $state(0);
</script>
<Count {count} />
<button onclick={() => count++}>Increment</button>
<!-- Count.svelte -->
<script>
let { count } = $props();
let local = $state(count);
let value = $derived(count);
</script>
<p>Local: {local} (アップデートされません)</p>
<p>Derived: {value} (アップデートされます)</p>
Count.svelte では let local = $state(count); と let value = $derived(count); を定義して表示してみますが、 local の方は数字を増やすボタンを押しても画面が更新されません。
これは渡されてくる props の値を $state で囲ってしまうと deeply reactive state proxy となってしまいます。 Svelte では deep state を dependencies に反映させるには $derived を使用する必要があります。
Playgroundもあるので実際に触って体験してみてください。
SvelteKit を使用してるとよくあるミスは params をみるときです。
<!-- src/routes/[slug]/+page.svelte -->
<script>
let { params } = $props();
let slug = $state(params.slug); // この Slug はページを遷移しても変更されません。
</script>
{#each [1,2,3] as page}
{#if slug === `page-${page}`}
<p>Page {page}</p>
{:else}
<p><a href="/page-{page}">Page {page}</a></p>
{/if}
{/each}
<p>{slug}<p>
上記のコードの例のようにページを遷移しても slug の変更を検知できなく、値が変わることがありません。
この場合は let slug = $derived(params.slug); を使用すると良いでしょう。
終わりに
@5.45.3 からはstate_referenced_locally の warning が発生してくれるので、気がつくことができます。
ですが warning を許容したいパターンも多いらしく、この warning を ignore する人もいるみたいです。
Table of contents
