【问题标题】:Cloned arrays affecting react state影响反应状态的克隆数组
【发布时间】:2020-10-10 23:13:24
【问题描述】:

我在我的 react 应用程序中克隆数组时遇到问题。

我将一个包含数据的数组导入到名为 ApplicationsData 的应用程序中。它是一个对象数组。

import ApplicationsData from '../Store/Applications';

App 组件具有以下状态:

constructor(props) {
    super(props);    
    this.state = { 
        isOn: true,
        untouchedApplications: [...ApplicationsData],
        applications: [...ApplicationsData],
        activeWindows: [...defaultActive],
        background: "#3a6ea5"
    };
}

我使用“...”扩展运算符克隆了包含数据的数组。

在我的上下文中,我有一个方法 - openApp - 它会更改 state.applications 中元素的属性。

openApp: (appID) => {
                let appIndex = this.state.applications.findIndex( el => el.id == appID);
                let clone = [...ApplicationsData];
                
                clone[appIndex].isActive = true;
                clone[appIndex].newProp = true;
                clone[appIndex].isMinimized = false;
                this.setState({applications: clone})
            },

每当我到达clone[appIndex].prop = value 时,state.applications 和 untouchedApplications 都会被该数据覆盖,尽管在 state 和 openApp 中都使用了扩展运算符。状态中的 untouchedApplications 数组不会在应用程序或方法中的任何地方使用,但也会被更新。此外,分配给克隆数组的 newProp 属性不存在于带有数据的原始数组中,但在将其添加到克隆数组后,确实会应用于两个数组。

我也尝试过使用Array.fromstate.applications.slice() 来创建克隆。我感觉有点迷茫,因为我确信这是克隆数组的正确方法。

对于混乱的代码缩进,我深表歉意。我不知道如何正确格式化它。第一行在其他行之前,或者所有行都以 8 个制表符开头。任何提示都值得赞赏。

【问题讨论】:

    标签: arrays reactjs ecmascript-6 spread-syntax use-context


    【解决方案1】:

    您正在使用的数组是对象数组。对象是引用类型,这意味着您的数组实际上包含对象的引用

    当您将数组传播到一个新数组中时,您并没有克隆对象,只是克隆了它们的引用,因此当您编写 clone[appIndex] 时,您引用了两个数组中包含的同一个对象强>。

    要解决这个问题,您可以使用map 方法克隆您要更改的对象:

    const newArray = ApplicationsData.map(
      (item, index) =>
        index == appIndex ?
          ({
             ...item,
             isActive: true,
             newProp: true,
             isMinimized: false
           }) : 
        item
    );
    

    这将返回所有项目的原始对象引用,您要更改的特定项目除外。在这种情况下,它会创建一个全新的对象并返回该引用,因此原始对象保持不变。

    【讨论】:

      【解决方案2】:

      你应该使用map函数

      (appID) => {
         let clone = this.state.applications.map(item => {
              if (item.id == appId) {
                  return {
                      ...item,
                      isActive: true,
                      newProp: true,
                      isMinimized: false
                  }
              }
              return item;
          })    
          this.setState({applications: clone})
      },
      

      这是因为当您使用 ... 运算符时,它会创建数组的浅拷贝而不是深拷贝。

      let val = [{key: "value"}, {key: "value"}, {key: "value"}]
      let copy = [...val];
      
      
      let isEqualShallow = val[0] == copy[0]
      
      console.log(isEqualShallow)

      因此您可以看到副本中的第一个对象如何与另一个对象相等。但是,如果您在内部对象上也使用扩展运算符,那么您会得到一个深层副本。

          let val = [{key: "value"}, {key: "value"}, {key: "value"}]
          let copy = val.map(item => {
            return {...item}
          })
      
      
          let isEqualDeep = val[0] == copy[0]
      
          console.log(isEqualDeep)

      【讨论】:

        猜你喜欢
        • 2018-03-08
        • 1970-01-01
        • 2018-02-07
        • 1970-01-01
        • 2011-12-11
        • 2020-11-11
        • 2011-01-30
        • 1970-01-01
        • 2014-08-04
        相关资源
        最近更新 更多