如何在 Svelte 中拼接后更新数组?
Posted
技术标签:
【中文标题】如何在 Svelte 中拼接后更新数组?【英文标题】:How to update an array after splice in Svelte? 【发布时间】:2020-03-16 17:54:12 【问题描述】:我正在学习 Svelte,并阅读了需要重新分配数组才能让组件或页面更新它的文档。为此,他们设计了一个更惯用的解决方案。而不是写:
messages.push('hello');
messages = messages;
你可以改写:
messages = [...messages, 'hello'];
好吧,有道理。但是文档说:
您可以使用类似的模式来替换 pop、shift、unshift 和 splice。
但是怎么做呢?我看不到如何从数组中删除项。更重要的是,我怎样才能更惯用地写以下内容?
messages.splice(messages.indexOf('hello'), 1);
messages = messages;
【问题讨论】:
Svelte 的反应是由分配触发的。因此推送、弹出、切片等不起作用。请在分配值时使用“=”。 【参考方案1】:你可以例如使用filter数组方法创建一个没有'hello'
元素的新数组:
messages = messages.filter(m => m !== 'hello');
【讨论】:
哦,这是一个优雅的解决方案!我实际上应该更好地学习所有 JS 数组函数以了解可能的情况。但是,是的,这将起作用。谢谢! :)【参考方案2】:如前所述,Svelte 的反应是由分配触发的。 current Svelte tutorial 使用 javascript 的 (ES6) spread syntax(三个点)将下一个更高的数字添加到数组中,提供比使用 push
的冗余分配更惯用的解决方案:
function pushNumber()
numbers = [...numbers, lastnumber]; // 1, 2, 3, 4, 5
您可以使用扩展语法替换 pop
、shift
、unshift
和 splice
,尽管在某些情况下这可能会增加操作的时间和复杂性:
function unshiftNumber()
numbers = [firstnumber, ...numbers]; // 0, 1, 2, 3, 4
function popNumber()
numbers = [...numbers.slice(0,numbers.length - 1)]; // 1, 2, 3
function shiftNumber()
numbers = [...numbers.slice(1,numbers.length)]; // 2, 3, 4
function spliceNumber()
numbers = [firstnumber, ...numbers.slice(0,numbers.length-1)];// 0, 1, 2, 3
不过,传播只是实现这一目标的一种方式。不使用 pop/push 等的目的是鼓励不变性。因此,例如,任何删除都可以只是一个过滤器。
【讨论】:
这是一个更规范的答案,虽然接受的答案确实完全回答了这个问题,但它更彻底并且指的是惯用的苗条......【参考方案3】:这里有几件事情需要考虑。 鉴于此代码:
messages.splice(messages.indexOf('hello'), 1);
messages = messages;
这里发生的事情是:
-
寻找字符串
"hello"
在数组中第一次出现
根据找到的索引从数组中删除此类元素。
这里的假设是"hello"
需要存在,否则可能会从数组中删除最后一个项(因为indexOf
返回-1
) .
因此,原始数组是变异的:取决于上下文,有时比将整个数组复制到新数组更可取;否则,通常最好避免这种突变。
所以。如果您希望完全具有这种行为,这可能是您可以拥有的最佳代码。以filter为例:
messages = messages.filter(message => message !== "hello")
这里发生的事情是:
-
过滤掉 any 元素等于
"hello"
返回一个没有此类元素的新数组
所以它与原始代码完全不同:首先,它总是循环整个数组。如果您有数千个元素,即使您在第二个索引处只有一个 "hello"
,它也会始终迭代所有元素。也许这是你想要的,也许不是。如果元素是唯一的,比如一个 id,也许你一旦找到它就想停下来。
其次,它返回一个新数组。同样,这通常比改变数组更好,但在某些情况下,最好改变它而不是创建一个新数组。
所以,如果你想改变原始数组,最好还是坚持原来的代码。
如果你不关心(比如push
的例子),我相信按照svelte开发者的意图,你的代码会大致翻译成:
let i = messages.indexOf("hello");
messages = [...messages.slice(0, i), ...messages.slice(i + 1)];
(仍然假设有 "hello"
消息并且您只对第一次出现感兴趣)。
很遗憾,JS 没有更好的语法来处理切片。
【讨论】:
完美回答每一个案例。【参考方案4】:您可以执行通常的push
和pop
或`在您的阵列上拼接
但是因为 Svelte 的响应是由赋值触发的,所以使用 push 和 splice 等数组方法不会自动导致更新。
根据All about Immutable Arrays and Objects in JavaScript,你可以这样做...
let messages = ['something', 'another', 'hello', 'word', 'another', 'again'];
const indexOfHello = messages.indexOf('hello');
messages = [...messages.slice(0, indexOfHello), ...messages.slice(indexOfHello + 1)];
注意splice和slice
的区别splice() 方法在数组中添加/删除项目,并返回 删除的项目。 注意:此方法会更改原始数组。 语法:
array.splice(start, deleteCount, itemstoAdd, addThisToo);
但是
slice() 方法将数组中的选定元素作为新数组对象返回。 slice() 方法选择从给定的 start 参数开始的元素,并在给定的 end 参数处结束,但不包括。 注意:原数组不会改变。
按顺序
它将数组的一部分的浅拷贝返回到新数组中 从头到尾选择的对象(不包括结尾)。原本的 数组不会被修改。 语法:
array.slice(start, end);
【讨论】:
【参考方案5】:如果你在徘徊,filter
也可以用于使用给定的index
删除元素:
let elements = ['a','b', 'c'];
let idx = 1;
elements = elements.filter( (e,i) => i !== idx );
// => ['a', 'c']
【讨论】:
【参考方案6】:传播拼接的数组以将其重新分配给自身;)
messages = [...messages.splice(messages.indexOf('hello'), 1)];
目标是让 Svelte 检测到数组 messages
(组件的属性或 Svelte 存储中的变量)已更改。这就是为什么数组messages
必须用let
或var
关键字声明,而不是const
。这样你就可以重新分配它。而重新赋值操作本身就足以让 Svelte 检测到数组发生了变化。
也许,仅仅这样做也可以:
messages = messages.splice(messages.indexOf('hello'), 1);
【讨论】:
hrm,这个不准确,splice方法原地修改数组,返回删除的元素developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…以上是关于如何在 Svelte 中拼接后更新数组?的主要内容,如果未能解决你的问题,请参考以下文章