Svelte5のルーンによる機能分析第二弾です。前回は$host
ルーンでしたが、今回は$bindble
ルーンです。$host
ルーンほど機能はややこしくないのですが、後述するように公式の説明が少しややこしいことをしています。
svelteには同期対象を取りたい場合、フォームに
<input bind:value={message}>
のような記述をします。Svelte5には$bindableルーンという新たな機能が搭載され、デモを確認してみると、子コンポーネントにフォームと全く同じ記述を確認できます。
<FancyInput bind:value={message} />
ですが、Svelte5になってからonディレクティブが廃止になり、ダイレクトに変数を他コンポーネントへ転送できるようになったので、正直こんな記述は不要じゃないか? そう思っていました。
これはどんな動きを意味しているのか?
それでも新たに登場した機能である以上、何か意味のある動きを持っているのでは?と思い、まずはデモ通り記述し、動作を確認してから、今度は自分が作成してみたプログラムに落とし込んでみました。
確かに子コンポーネントから入力した値が、親コンポーネント上に値が装飾されて表示されます。
実証
毎回valueを変数に使うのは面倒だし、フォームでしか使えないのならばあまり実用的じゃないなあと訝っているうちに、あることを思いつき実験してみました(変数hogeは最初からじゃありません)。
<script>
import Child from './child.svelte'
let mes = $state("")
</script>
<main>
<Child bind:hoge={mes} />
<p>親:{ mes }</p>
</main>
<script>
let {hoge = $bindable("") } = $props()
</script>
<main>
<input bind:value={hoge} />
<p>子:{ hoge }</p>
</main>
おわかりいただけただろうか
子コンポーネントから受け渡したデータを親コンポーネントに伝播、更にそこから再度子コンポーネントへ値が伝播されています。つまり、親コンポーネントからも子コンポーネントからも、全く同じメッセージが出力されます。
結論
公式チュートリアルが少々紛らわしいことをしているだけで、子コンポーネントタグに用意されているbind:valueは、inputタグのbind:valueプロパティとは厳密には別物で、フォーム以外に値を表示させる場合は、bindディレクティブで設定するキーにどんな値を指定してもいいのです。そして、$bindableルーンを使用することで、任意の変数を自在に、逆方向へ(子から親)も、自由自在にデータバインディングできるようになります。
ただし、公式も注意を入れているようにJSフレームワークは基本的にストリーム(川の流れ)の概念があり、上流から下流へデータを伝播させていくものなので、このようにデータを逆流させるような機能は、必要なとき以外使用することを推奨していないようです。
使用する場面としては、繰り返し作成された各種部品におけるイベント制御(電卓やカレンダーなど)などかな、と思います。