Basic Svelte
Bindings
Classes and styles
Advanced Svelte
Advanced reactivity
Motion
Advanced bindings
Advanced transitions
Context API
Special elements
<script module>
Next steps
Basic SvelteKit
Introduction
Routing
Loading data
Headers and cookies
Shared modules
API routes
$app/state
Errors and redirects
Advanced SvelteKit
Page options
Link options
Advanced routing
Advanced loading
Environment variables
Conclusion
デフォルトでは、each ブロックの値を更新すると、そのサイズが変更された場合はブロックの 末尾 に DOM ノードが追加・削除され、そして残った DOM に変更された値が更新されます。これはあなたが期待した動作ではないかもしれません。
説明するより見ていただいたほうがおわかり頂けるでしょう。Thing.svelte の中を見てみると、name は動的な prop ですが emoji は定数です。
‘Remove first thing’ ボタンを何回かクリックすると、以下のことが発生します:
- 一番最後のコンポーネントが削除される
- 残りの DOM ノードの
nameの値が更新される (‘doughnut’ を含んでいたテキストノードが ‘egg’ を含むようになる、など) が、絵文字は更新されない
もしあなたが React を経験しているなら、奇妙に見えるかもしれません。なぜなら、あなたは state が変更されたらコンポーネント全体が再レンダリングされることに慣れているからです。Svelte の動作は異なります: コンポーネントは一度だけ実行され、その後の更新は ‘きめ細やかに(fine-grained)’ 行われます。これにより、より高速に、よりコントロールしやすくなります。
これを修正する方法の1つとしては、emoji を $derived の値にすることが考えられます。しかし、末尾の <Thing> コンポーネントを削除して全てを更新するより、先頭の <Thing> コンポーネントを完全に削除するほうが、理にかなっています。
そのためには、each ブロックの each イテレーションに一意な key を指定します。
{#each things as thing (thing.id)}
<Thing name={thing.name}/>
{/each}Svelte は内部的に
Mapを使用しているので、どんなオブジェクトでもキーとして使用できます。つまり(thing.id)の代わりに(thing)を使うことができます。しかし、文字列または数値を使用する方が一般的に安全です。なぜなら、例えばAPIサーバーからの新しいデータで更新する場合に、参照が等しくなくても同一性が持続することを意味するからです。
<script>
import Thing from './Thing.svelte';
let things = $state([
{ id: 1, name: 'apple' }, { id: 2, name: 'banana' }, { id: 3, name: 'carrot' }, { id: 4, name: 'doughnut' }, { id: 5, name: 'egg' }]);
</script>
<button onclick={() => things.shift()}>Remove first thing
</button>
{#each things as thing} <Thing name={thing.name} />{/each}