React状态对象中的值发生奇怪的变化

时间:2019-10-05 08:44:40

标签: javascript reactjs react-redux

我是React的新手,我想知道当我在其中复制对象时何时影响状态对象。

在以下代码中;第一种情况导致状态对象被更新,而第二种情况不是。 我需要知道有什么区别以及为什么会发生这种情况?

import React, { Component } from "react";

export class Test extends Component {
  state = {
    counters: [
      { id: 1, desc: "Item1 default description" },
      { id: 2, desc: "Item2 default description" }
    ]
  };
  handleAction() {
    const counters = { ...this.state.counters };

    ////First Scenario
    console.log("Item description before updating:", counters[0].desc);
    counters[0].desc = "Item1 description updated successfully!"; //<--This line makes the state updated
    console.log("Item description after updating:", counters[0].desc);
    console.log(
      "Item description value in state object:",
      this.state.counters[0].desc //Item value is updated in the state object.
    );

    ////Second Scenario

    // console.log("Item description before updating:", counters[0].desc);
    // counters[0] = { id: 1, desc: "Item1 description updated successfully!" }; //<--This line does NOT affect the state
    // console.log("Item description after updating:", counters[0].desc);
    // console.log(
    //   "Item description value in the state object:", //Item value is NOT updated in the state object.
    //   this.state.counters[0].desc
    // );
  }

  render() {
    return (
      <React.Fragment>
        {this.state.counters[0].desc}
        <button
          className="btn btn-danger btn-sm"
          onClick={() => this.handleAction()}
        >
          Check Item description in state object
        </button>
      </React.Fragment>
    );
  }
}

3 个答案:

答案 0 :(得分:2)

在JS中,对象是passed by reference。并且以下语法复制该数组,但不复制存储在其中的对象。它称为浅表副本。

const counters = { ...this.state.counters };

在第一种情况下,您正在更新对对象的引用,该对象也被state变量引用。

但是,当您分配数组的元素时,您正在创建state不知道的新对象,因此它不会被修改。

答案 1 :(得分:0)

您需要使用setState更新状态。直接更改状态是您不应该做的事情:https://reactjs.org/docs/state-and-lifecycle.html#do-not-modify-state-directly

答案 2 :(得分:0)

传播运算符{ ...obj }进行浅表复制,这意味着在这种情况下它仅复制计数器数组的结构,而不复制每个元素的内容。

意味着counter[0]counter[1]的地址或引用是重复的,而不是它们所保存的对象。因此,更新counter[0].desc也将更新原始状态对象中的desc属性。

但是更新counter[0]仅更新重复项,不会影响状态对象中的原始副本。

选中this post,以更好地理解浅层副本和深层副本。

我还必须补充一点,您应该始终使用this.setState更新反应状态,以避免意外结果。

最后,有些人会争论使用嵌套属性,因为React不适合使用嵌套状态。也许这是正确与否,但这是我的想法:

我建议您避免使用嵌套状态,如果您必须尽力使其尽可能轻便,因为不利之处在于每一个微小的更改都会重新创建父对象,这不利于性能。