为何起作用:使用传播运算符更新状态下的数组元素

时间:2019-08-22 12:59:50

标签: javascript reactjs ecmascript-6

在阅读React Cookbook时,我偶然发现了一个代码片段,当用户检查TODO列表中已完成的任务时,就会调用此函数:

  markAsCompleted = id => {
    // Finding the task by id...
    const foundTask = this.state.items.find(task => task.id === id);

    // Updating the completed status...
    foundTask.completed = true;

    // Updating the state with the new updated task...
    this.setState({
      items: [
        ...this.state.items,
        ...foundTask
      ]
    });
  }

UPD :不知何故,我完全错过了 foundTask 上的价差运算符。因此,真正发生的是状态仅使用 ... this.state.items (已突变)进行更新,而 ... foundTask 部分没有进入状态,因为它不是有效的价差。

起初看起来应该将一个新元素添加到 items 数组中,而不是进行更新,所以我去了JS控制台进行检查:

state = { items: [{id: '0', done: false}, {id: '1', done: false}] }

upd = state.items.find(obj => obj.id === '0') // {id: "0", done: false}

upd.done = true // also updates object inside the array

state = { items: [...state.items, upd] }

/* Indeed, adds a new element:
items: Array(3)
0: {id: "0", done: true}
1: {id: "1", done: false}
2: {id: "0", done: true}
*/

因此,我已经downloaded the code并在本地运行了。而且,令我惊讶的是,它奏效了!状态正在更新,没有任何麻烦,没有多余的元素出现。我使用React DevTools在测试时查看实时状态。

我在网上搜索,但找不到书中的任何示例,但有更好的解释。通常,所有解决方案都涉及使用.map()构建新数组,然后替换现有数组(例如https://stackoverflow.com/a/44524507/10304479)。

我在书本代码段和控制台测试之间看到的唯一区别是React使用的是.setState(),所以也许这可以有所帮助。任何人都可以帮助澄清,为什么它起作用?

谢谢!

1 个答案:

答案 0 :(得分:0)

Array.find将返回数组中匹配的第一个值。在这里,数组由对象组成,返回的值将是对该对象的引用。

const foundTask = this.state.items.find(task => task.id === id);

此处foundTask将引用state.items中包含的同一对象。因此,当您修改foundTask时,您正在修改的对象与state.items中的对象相同。

例如,

如果this.state.items[{ id: 1 }],如果是

const foundTask = this.state.items.find(obj => obj.id === 1);
foundTask.id = 2;
console.log(this.state.items); // [{ id:2 }]

在代码中,

this.setState({
  items: [
    ...this.state.items,
    ...foundTask
  ]
});

这将使用任务的更新的completed值更新状态。 ...foundTask将在控制台中给您一个错误,因为foundTask将是一个对象,并且您将其散布在一个数组中。

这里没有...foundTask将产生相同的结果。也许没有错误。