【问题标题】:Create a immutable copy of a property创建属性的不可变副本
【发布时间】:2018-07-18 02:55:54
【问题描述】:

我有一种情况,我想制作一个不可更改的属性副本,以将状态恢复到其原始状态......良好状态。

我有一个 group 对象数组。
在每个group 中,我都有items 的数组。
当我在下面制作副本时,一切都很好。

我从这样做开始。

componentDidMount(){
    // originalGroups = Object.assign([], this.props.modalitygroups);
    originalGroups = JSON.parse(JSON.stringify(this.props.modalitygroups));
},

我已经尝试了上述两种说法,但读到当前活动的说法对对象进行了真正的深拷贝。不用说它确实正确复制了它。

然后我有这个搜索功能来搜索组和项目中的项目。

_searchFilter:function(search_term){
    this.setState({modalitygroups:originalGroups});
    let tempGroups = Object.assign([], this.state.modalitygroups);

    if(search_term !== ''){
        for (let x = (tempGroups.length) - 1; x >= 0; x--)
        {
            console.log("originalGroups",x,originalGroups);

            for (let i = (tempGroups[x].items.length) - 1; i >= 0; i--)
            {
                if(!tempGroups[x].items[i].description.toLowerCase().includes(search_term.toLowerCase())){
                    tempGroups[x].items.splice(i,1);
                }
            }
            if(tempGroups[x].items.length === 0){
                tempGroups.splice(x, 1);
            }
        }
        this.setState({modalitygroups:tempGroups});
    }
},

因此,我首先恢复原始状态以启用对所有内容的搜索。搜索功能循环遍历每个组,并且在每个组循环中循环遍历每个项目,删除不包含搜索短语的项目。
遍历每个项目后,如果组中没有任何项目,我也会从 group 数组中删除该组。

这在第一次使用时效果很好。

但是当我开始搜索新项目时,我发现originalGroups 也发生了变化。先前删除的items 也已从unchangable 副本中删除,我不知道为什么。它在哪里以及为什么会更改我的安全副本?

希望这是有道理的。

【问题讨论】:

  • Object.assign 不会创建深层复制
  • 你也可以使用 Object.create 来复制一个对象。

标签: javascript reactjs immutability


【解决方案1】:

所以模态组包含原始组?这很难理解......我不会“保存”原始组,而是将 this.props.modalitygroups 单独保留并复制到该州的filteredGroups。你可以从你永远不会改变的道具中重新加载它。

当您执行let tempGroups = Object.assign([], this.state.modalitygroups); 时,在您的过滤器函数中,这可能应该是您使用 json 创建深层副本的地方。那就是用旧数组中相同的组引用填充新数组,因此您正在修改原始数组中的相同组实例。

_searchFilter:function(search_term){
    // deep copy
    let tempGroups = JSON.parse(JSON.stringify(this.props.modalitygroups));

    if(search_term !== ''){
        for (let x = (tempGroups.length) - 1; x >= 0; x--)
        {
            console.log("originalGroups",x,originalGroups);

            for (let i = (tempGroups[x].items.length) - 1; i >= 0; i--)
            {
                if(!tempGroups[x].items[i].description.toLowerCase().includes(search_term.toLowerCase())){
                    tempGroups[x].items.splice(i,1);
                }
            }
            if(tempGroups[x].items.length === 0){
                tempGroups.splice(x, 1);
            }
        }
        this.setState({modalitygroups:tempGroups});
    }
},

【讨论】:

  • 问题是,我试过了。但由于某种原因this.props.modalitygroups 也发生了变化。它丢失物品的原因我还不知道。
  • 是的,this.props.modalitygroups 包含原始组。
  • 你做了哪些选择?如果你在过滤器中使用filteredGroups = JSON.parse(JSON.stringify(originalGroups)) 并设置一个不同的 状态属性(如filteredGroups),你应该没问题。
【解决方案2】:

const state = {
  property1: 42
};

const originalGroups = Object.freeze(state);

originalGroups.property1 = 33;
// Throws an error in strict mode

console.log(originalGroups.property1);
// expected output: 42

毕竟ReactJS 本质上还是javascript,所以你可以申请Object.freeze 来保存状态副本

【讨论】:

  • 这不会冻结孩子的属性,如果property1是一个你不能改变property1的数组,但是你可以在数组中添加或删除对象,除非你也冻结它对吧?
  • @JasonGoemaat:据此:stackoverflow.com/a/7510003/9816472,它应该也可以正常工作,但是我还没有测试出来
  • 嗯...不确定它有多深,但在 Chrome 中似乎在严格模式下达到 1 级...fiddle。这里不能改变数组或者name属性,但是可以改变phone.mobile:var arr = Object.freeze([{name: 'Isaac', phone: {mobile: '7025551212'}}]);
  • @JasonGoemaat:有趣的发现,但可能就像评论所有者提到的那样是实现问题,但如果它是一级深度冻结,我相信它足以处理 OP 的请求,对吧?
  • 我不知道。这将阻止他从原始数组中删除组,但可能不会从子属性中删除项目。它可能会通过抛出错误来帮助他找到问题。如果它在Object.assign([], this.state.modalitygroups); 中,那会失败,还是对冻结的“组”对象进行浅拷贝?
猜你喜欢
  • 1970-01-01
  • 2013-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多