Svelteで親ComponentからのpropsのReactivityを失ってしまうパターン
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>
<p></p> 上記のコードの例のようにページを遷移しても slug の変更を検知できなく、値が変わることがありません。
この場合は let slug = $derived(params.slug); を使用すると良いでしょう。
終わりに
@5.45.3 からはstate_referenced_locally の warning が発生してくれるので、気がつくことができます。
ですが warning を許容したいパターンも多いらしく、この warning を ignore する人もいるみたいです。
