我不理解教程中的这一部分:https://svelte.dev/tutorial/keyed-each-blocks.
我可以看到things
数组已正确更新,因此正确的thing.color
按预期传递。但是通过第一句";默认情况下,修改each
块的值时,它将在块末尾添加和删除项目,并更新任何已更改的值&";,似乎是说Svelte在点击按钮时无论如何都会删除最后一个块,然后剩下的4个块将面对切片的things
,这就是
[{ id: 2, color: '#6a00a8' },
{ id: 3, color: '#b12a90' },
{ id: 4, color: '#e16462' },
{ id: 5, color: '#fca636' }]
由于initial
被声明为const
,因此它不能再更新,因此thing.id
1-4的颜色仍然存在。
这是正确的理解吗?这是假设each
块是可交换的默认行为吗?
然后它说使用thing.id
作为each
块的密钥将解决问题,即{#each things as thing (thing.id)}
。我不明白each
块中的密钥是如何使用的,如果没有提供thing.id
,默认密钥是什么。以及为什么默认密钥(如果有,或者默认的无密钥)在提供thing.id
时不起作用。
谢谢你的澄清。
我相信当您不提供键时,它会使用类似于项的索引之类的东西作为默认值。这可以通过使用进行验证
{#each things as thing, index (index)}
<Thing current={thing.color}/>
{/each}
这给出了与最初不使用密钥相同的行为。
让我们将为id: 1
渲染的<Thing>
称为Thing1
,依此类推
没有提供钥匙
当我们从列表中删除第一个项目时,Thing1
仍然保持不变,因为与它相关联的键(在本例中为索引)保持不变。先前发送到Thing2
的道具现在被发送到CCD20。这种情况一直在发生。但是现在少了一个元素,Thing5
就从DOM中删除了。
与密钥"CCD_ 22"相关联的组件CCD_;0";(Thing1
)在移除第一个项目时不被销毁。发生这种情况是因为键保持不变(新数组在索引0处也有一个项)。只有发送到Thing1
的道具发生了更改,使initial
变量与id: 1
原始项的颜色保持一致。
提供了(thing.id)密钥
当具有id: 1
的事物被移除时,不存在映射到"0"的Thing
的任何实例;1〃;。因此,Thing1
被从DOM中移除。
另一种理解方式是,当你给出一个关键帧时,你实际上是在告诉Svelte将每个渲染块映射到该关键帧。当该键不存在时,去掉该块并将其从DOM中删除。但是,如果关键点保持不变,道具发生变化,则更新道具,而不是重新创建块。
如果未指定键,则会使用列表的索引作为键。因此,如果你从列表中删除项目,它不会重新创建或排序块,只会更新道具。
API文档这样解释:
如果提供了一个密钥表达式——它必须唯一地标识每个列表项——Svelte将在数据更改时使用它来区分列表,而不是在末尾添加或删除项。键可以是任何对象,但建议使用字符串和数字,因为它们允许在对象本身发生更改时保持身份。
{#each items as item (item.id)} <li>{item.name} x {item.qty}</li> {/each} <!-- or with additional index value --> {#each items as item, i (item.id)} <li>{i + 1}: {item.name} x {item.qty}</li> {/each}
我发现这在教程中也缺乏适当的解释。然而,我认为文档更清楚——可以为每个函数提供一个唯一的键,这样每个迭代都是唯一标识的。因此,当从提供给每个函数的数据,可以识别并删除正确的迭代。
我也很难理解这个例子,为什么图标没有改变。我注意到初始化后在组件中计算的值(const emoji = emojis[name]
)保持不变,但如果我们使用反应声明:$: emoji = emojis[name];
值将被重新计算,这个例子运行良好。
有同样的怀疑,然后我意识到什么"它将在块"的末尾添加和删除项目;这可能意味着这里可能适用于DOM,因此即使在JavaScript中删除数组的第一个项,Svelte也总是删除最后一个DOM节点。通过提供密钥,DOM和JavaScript都可以执行相同的操作。
无论何时在{#each} {/each}
中使用嵌套组件,如果存在多个组件,svelte都需要一种单独识别每个组件的方法。它通过在内部为它们分配一个键来实现这一点。如果要操作这些组件,可以显式地为它们指定关键帧,以便识别它们。
那里发生的事情是,由于没有明确定义键,它计算"事物"的大小并显示它们。每当您减小"things"的大小时,它会再次从顶部重申为"things的大小",而不是选择相应的<Thing>
,因为您没有绑定它们。您需要将<Thing>
与'things'元素中的东西绑定,以便可以根据'things'
元素的值进行操作。
在该示例中,使用CCD_ 36作为密钥进行识别。你也可以使用类似(thing.hashCode())
的东西,结果会是一样的。任何导致唯一标识并绑定到"事物"的东西都可以。