【问题标题】:Why is this working: updating array element in state with spread operator为什么会这样:使用扩展运算符更新状态中的数组元素
【发布时间】:2019-08-22 22:56:59
【问题描述】:

在阅读 React Cookbook 时,我偶然发现了一段代码 sn-p,当用户在 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)。

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

谢谢!

【问题讨论】:

    标签: javascript reactjs ecmascript-6


    【解决方案1】:

    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 将产生相同的结果。也许没有错误。

    【讨论】:

    • 哦,我完全错过了,他们还传播了foundTask!现在有道理了,谢谢。所以书籍代码中有一个错误 - 它只是没有在视觉上显示出来。
    • 是的,如果它与您的问题相同。您应该运行代码并检查控制台。
    • @Alhxor 你似乎是这个网站的新手。如果您发现任何答案有帮助或看起来像是您正在寻找的解决方案,您可以投票或将其标记为已接受。您无需编辑问题即可将答案放入其中?
    • 是的,第一个问题。还没有足够的代表进行投票以进行注册。再次感谢。 :)
    猜你喜欢
    • 2020-08-09
    • 2019-09-23
    • 2018-06-25
    • 1970-01-01
    • 2019-07-27
    • 2020-07-14
    • 1970-01-01
    • 2018-12-09
    • 2015-07-07
    相关资源
    最近更新 更多