【问题标题】:How to update an array after splice in Svelte?如何在 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 的反应是由分配触发的。因此推送、弹出、切片等不起作用。请在分配值时使用“=”。

标签: javascript arrays 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
}

您可以使用扩展语法替换 popshiftunshiftsplice,尽管在某些情况下这可能会增加操作的时间和复杂性:

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;

这里发生的事情是:

  1. 寻找字符串"hello"在数组中第一次出现
  2. 根据找到的索引从数组中删除此类元素。

这里的假设是"hello"需要存在,否则可能会从数组中删除最后一个项(因为indexOf返回-1) .

因此,原始数组是变异的:取决于上下文,有时比将整个数组复制到新数组更可取;否则,通常最好避免这种突变。

所以。如果您希望完全具有这种行为,这可能是您可以拥有的最佳代码。以filter为例:

messages = messages.filter(message => message !== "hello")

这里发生的事情是:

  1. 过滤掉 any 元素等于"hello"
  2. 返回一个没有此类元素的数组

所以它与原始代码完全不同:首先,它总是循环整个数组。如果您有数千个元素,即使您在第二个索引处只有一个 "hello",它也会始终迭代所有元素。也许这是你想要的,也许不是。如果元素是唯一的,比如一个 id,也许你一旦找到它就想停下来。 其次,它返回一个新数组。同样,这通常比改变数组更好,但在某些情况下,最好改变它而不是创建一个新数组。

所以,如果你想改变原始数组,最好还是坚持原来的代码。

如果你不关心(比如push的例子),我相信按照svelte开发者的意图,你的代码会大致翻译成:

let i = messages.indexOf("hello"); 
messages = [...messages.slice(0, i), ...messages.slice(i + 1)];

(仍然假设有 "hello" 消息并且您只对第一次出现感兴趣)。

很遗憾,JS 没有更好的语法来处理切片。

【讨论】:

  • 完美回答每一个案例。
【解决方案4】:

您可以执行通常的pushpop 或`在您的阵列上拼接

但是因为 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)];

注意spliceslice

的区别

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 必须用letvar 关键字声明,而不是const。这样你就可以重新分配它。而重新赋值操作本身就足以让 Svelte 检测到数组发生了变化。

      也许,仅仅这样做也可以:

      messages = messages.splice(messages.indexOf('hello'), 1);
      

      【讨论】:

      猜你喜欢
      • 2022-11-14
      • 2022-09-30
      • 2018-10-06
      • 1970-01-01
      • 2020-11-19
      • 2015-09-16
      • 2019-06-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多