跳至主要內容

預設情況下,當你修改 `each` 區塊的值時,它會在區塊的*結尾*新增和移除 DOM 節點,並更新任何已變更的值。這可能不是你想要的。

用示範來解釋會比用文字解釋來得容易。在 `Thing.svelte` 內,`name` 是一個動態 prop,但 `emoji` 是一個常數。

點擊「移除第一個項目」按鈕幾次,並注意發生什麼事

  1. 它會移除最後一個元件。
  2. 然後它會更新剩餘 DOM 節點中的 `name` 值,但不會更新 emoji。

如果你是從 React 來的,這可能會覺得很奇怪,因為你習慣當狀態變更時整個元件重新渲染。Svelte 的運作方式不同:元件會「執行」一次,後續的更新是「細粒度」的。這使得速度更快,並給予你更多的控制權。

一種修復方法是將 `emoji` 變成一個`$derived` 值。但與其移除*最後一個*元件並更新所有其他元件,不如直接移除第一個 `<Thing>` 元件更有意義。

若要這麼做,我們需要為 `each` 區塊的每次迭代指定一個唯一的*鍵值*

App
{#each things as thing (thing.id)}
	<Thing name={thing.name}/>
{/each}

你可以使用任何物件作為鍵值,因為 Svelte 在內部使用 `Map` — 換句話說,你可以使用 `(thing)` 而不是 `(thing.id)`。然而,使用字串或數字通常更安全,因為它表示身分可以持續存在,而無需參考相等性,例如當從 API 伺服器更新新鮮資料時。

在 GitHub 上編輯此頁面

上一個 下一個
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<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}