问题描述
我正在尝试绑定{#each}
块中的元素,并通过单击删除它们。 <script>
const foodList = [
{ icon: '🍲', elem: null, },
{ icon: '🥫', elem: null, },
{ icon: '🍔', elem: null, },
];
const remove = (index) => {
foodList.splice(index, 1);
foodList = foodList;
};
</script>
{#each foodList as {icon, elem}, index}
<div
bind:this={elems[index]}
on:click={remove}
>
{icon}
</div>
{/each}
在我的代码中有两个问题:
{#each}
使迭代次数增加两倍- 通过单击绑定的元素删除数组中的项后-svelte触发错误&无法设置未定义&的属性
为什么是这样工作的?
推荐答案
我写这篇文章不是为了寻求帮助,而是为了帮助那些遇到同样问题的人
这两个问题都有相同的根源,所以我在这里收集它们:
- 有时
{#each}
块的工作比预期的多两倍 - 有时
{#each}
阻止绑定引发错误
在Svelte编译器3.44.1版中测试的所有代码
问题1-每个人工作两次
我是什么意思?
- 每个块进行两次所有迭代
让我告诉您,看看下面的代码,{#each}
可以迭代多少次?
<script>
const foodList = [
{ icon: '🍲' },
{ icon: '🥫' },
{ icon: '🍔' }
];
</script>
{#each foodList as {icon}}
<div> {icon} </div>
{/each}
如果您的答案是-3,那么恭喜您,您是对的。
好的,现在我们需要绑定我们在{#each}
块中呈现的元素。
这是相同的代码,只是在{#each}
请查看下面,然后重试,{#each}
需要迭代多少次?
<script>
const foodList = [
{ icon: '🍲', elem: null, },
{ icon: '🥫', elem: null, },
{ icon: '🍔', elem: null, }
];
</script>
{#each foodList as {icon, elem} }
<div
bind:this={elem}
>
{icon}
</div>
{/each}
对……我们有6次迭代,两次更多。
首先添加一些console.log()
{#each}
块代码即可看到,如下所示:
{#each foodList as {icon, elem}, index}
{console.log('each iteration: ', index, icon) ? '' : ''}
<div
bind:this={elem}
>
{icon}
</div>
{/each}
这是因为我们对{#each}
迭代和绑定使用了相同的数组。
如果我们创建用于绑定的新数组,问题将消失:
<script>
const foodList = [
{ icon: '🍲' },
{ icon: '🥫' },
{ icon: '🍔' }
];
const elems = [];
</script>
{#each foodList as {icon}, index }
{ console.log('each iteration: ', index, icon) ? '' : ''}
<div
bind:this={elems[index]}
>
{icon}
</div>
{/each}
对..。现在问题解决了,我们得到了3次迭代,正如我们预期的。
正如我试图找出的那样,这是一个活了很长时间的细菌--至少一年。随着OUT代码变得更加复杂,这会在不同的情况下导致不同的问题。
问题2-在对可迭代数组进行切片后,每个绑定都会引发错误
(类似于:‘无法设置未定义的属性’)
我是什么意思?
- 在删除一个可迭代数组项后,每个块绑定都会引发错误
相同的示例,只是在其元素上添加了删除数组项点击:
<script>
const foodList = [
{ icon: '🍲', elem: null, },
{ icon: '🥫', elem: null, },
{ icon: '🍔', elem: null, }
];
const remove = (index) => {
foodList.splice(index, 1);
foodList = foodList;
};
</script>
{#each foodList as {icon, elem}, index}
{console.log('each iteration: ', index, icon) ? '' : ''}
<div
bind:this={elem}
on:click={remove}
>
{icon}
</div>
{/each}
我们预计,如果我们单击div
-数组项,它绑定到的数组项将被切片,我们将在屏幕上丢失它们。正确..。但我们得到了错误,因为{#each}
块使仍然是3次迭代,而不是我们等待的2次迭代。同样为了清晰起见,我们的代码步骤是:foodList长度为3->;我们点击食物图标->;foodList长度为2(我们用点击的图标剪切项目)。
之后{#each}
应该重复2次以呈现foodList中的每个左侧图标,但他却重复了3次!
这就是我们遇到问题的原因,我们的代码试图将新属性写入未定义的(项被切片,因此当我们尝试读写它时-存在未定义的。
这是一个错误,如果我们对{#each}
迭代和绑定使用相同的数组,则会发生错误。
对我的问题最干净利落的解决办法是将可迭代数据和绑定数据分离到不同的数组中:
<script>
const foodList = [
{ icon: '🍲' },
{ icon: '🥫' },
{ icon: '🍔' }
];
let elems = [];
const remove = (index) => {
foodList.splice(index, 1);
foodList = foodList;
};
</script>
{#each foodList as {icon, cmp}, index}
{console.log('each iteration: ', index, icon) ? '' : ''}
<div
bind:this={elems[index]}
on:click={remove}
>
{icon}
</div>
{/each}
但是...让我们通过添加$: console.log(elems);
elems
数组(它是反应式表达式,每次更改时都会打印elems
数组)
<script>
const foodList = [
{ icon: '🍲' },
{ icon: '🥫' },
{ icon: '🍔' }
];
let elems = [];
const remove = (index) => {
foodList.splice(index, 1);
foodList = foodList;
};
$: console.log(elems);
</script>
{#each foodList as {icon, cmp}, index}
{console.log('each iteration: ', index, icon) ? '' : ''}
<div
bind:this={elems[index]}
on:click={remove}
>
{icon}
</div>
{/each}
看起来像是有两条新闻要告诉您
- 我们没有收到错误
- 我们在
elems
数组中有新的null
项
这意味着问题仍然存在({#each}
块仍然使切片项多迭代一次)。
目前我们可以在foodList切片后过滤elems
数组,只能在页面更新后进行,如tick()
。
完整代码:
<script>
import { tick } from 'svelte';
const foodList = [
{ icon: '🍲', elem: null, },
{ icon: '🥫', elem: null, },
{ icon: '🍔', elem: null, }
];
let elems = [];
const remove = async (index) => {
foodList.splice(index, 1);
foodList = foodList;
await tick();
elems = elems.filter((elem) => (elem !== null));
};
$: console.log(elems);
</script>
{#each foodList as {icon, elem}, index}
{console.log('each iteration: ', index, icon) ? '' : ''}
<div
bind:this={elems[index]}
on:click={remove}
>
{icon}
</div>
{/each}
请记住:{#each}
块仍然可以额外工作1次,我们的绑定元素为空,我们只是在页面更新后对其进行了筛选。
最后一站
真的不知道该说什么.我在这上面浪费了太多时间*试图找出为什么我的代码不能正常工作。
我喜欢苗条,但我不喜欢虫子
我真的希望这本小指南能帮助你们中的一些人节省很多时间。
将很高兴看到您的更正,再见,不要让🐞获胜。
P.S.
是的,这需要时间,但是..。永远不知道什么时候需要帮助,分享你的知识这篇关于Svelte每个工作两次/每个绑定错误(不能设置未定义的属性)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!