默认情况下,当你修改 each
块的值时,它会在块的末尾添加和删除 DOM 节点,并更新任何已更改的值。这可能不是你想要的。
用示例说明比解释更容易。在 Thing.svelte
中,name
是一个动态 prop,但 emoji
是一个常量。
点击“移除第一个事物”按钮几次,注意会发生什么。
- 它删除了最后一个组件。
- 然后它更新了剩余 DOM 节点中的
name
值,但没有更新 emoji。
如果你来自 React,这可能看起来很奇怪,因为你习惯于在状态更改时整个组件重新渲染。Svelte 的工作方式不同:组件“运行”一次,随后的更新是“细粒度的”。这使得事情变得更快,并让你有更多的控制权。
一种解决方法是使 emoji
成为 $derived
值。但删除第一个 <Thing>
组件本身比删除最后一个组件并更新所有其他组件更有意义。
为此,我们为 each
块的每次迭代指定一个唯一的键。
应用
{#each things as thing (thing.id)}
<Thing name={thing.name}/>
{/each}
你可以使用任何对象作为键,因为 Svelte 在内部使用
Map
——换句话说,你可以使用(thing)
而不是(thing.id)
。然而,使用字符串或数字通常更安全,因为它意味着身份在没有引用相等的情况下仍然存在,例如当使用来自 API 服务器的新数据进行更新时。
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}