如何更新不可变列表以获取新列表
How to update immutable List to get a new List
我有一个不可变的 Map
,如下所示
var mapA = Map({
listA: List.of({
id: 1,
name: 'Name A',
selected: false
}, {
id: 2,
name: 'Name B',
selected: false
})
});
我想更新列表中的键 selected
。根据 immutable.js 文档 list.update
.
Returns a new List with an updated value at index with the return
value of calling updater
但是,如果我这样做
var listB = mapA.get('listA').update(1, function (item) {
item.selected = true;
return item;
});
然后,检查对象是否相等,它给了我 true
。
console.log(listB === x.get('listA')); // true
我在这里做错了什么? immutable.js 不就是这样吗?
您也需要更新地图。
var mapB = mapA.update('listA', function(item) {
return item.update(1, function(item) {
item.selected = true;
return item;
});
});
问题是您在不可变列表中使用了 可变 值。对于列表,对象没有改变,因为 oldObject === newObject
仍然是 true.
这是一个简化的例子:
> var obj = {};
> var list = Immutable.List.of(obj);
> list2 = list.update(0, function(obj) { obj.foo = 42; return obj;});
> list2.get(0)
Object { foo: 42 }
> obj
Object { foo: 42 }
> list.get(0) === list2.get(0)
true
要解决此问题,除了还要更新地图(如果需要的话),您还必须
- 更新时克隆对象
- 使用地图而不是对象
- 在这种情况下可能最好:使用 record 而不是对象
示例:
var MyRecord = new Immutable.Record({id: null, name: '', selected: false});
var mapA = Immutable.fromJS({
listA: [
new MyRecord({
id: 1,
name: 'Name A'
}),
new MyRecord({
id: 2,
name: 'Name B'
})
]
});
var mapB = mapA.updateIn(['listA', 1], function(record) {
return record.set('selected', true);
});
console.log(mapB.get('listA') === mapA.get('listA')); // false
这是我的发现。问题是 List
,它基本上是普通 JavaScript 对象的集合。哪些是可变的。
解决方法很简单,我把初始对象创建改成这样
var mapA = Immutable.fromJS({
listA: [{
id: 1,
name: 'Name A',
selected: false
}, {
id: 2,
name: 'Name B',
selected: false
}]
});
现在,以下内容按预期工作。
var mapB = mapA.setIn(['listA', 1, 'selected'], true);
我有一个不可变的 Map
,如下所示
var mapA = Map({
listA: List.of({
id: 1,
name: 'Name A',
selected: false
}, {
id: 2,
name: 'Name B',
selected: false
})
});
我想更新列表中的键 selected
。根据 immutable.js 文档 list.update
.
Returns a new List with an updated value at index with the return value of calling updater
但是,如果我这样做
var listB = mapA.get('listA').update(1, function (item) {
item.selected = true;
return item;
});
然后,检查对象是否相等,它给了我 true
。
console.log(listB === x.get('listA')); // true
我在这里做错了什么? immutable.js 不就是这样吗?
您也需要更新地图。
var mapB = mapA.update('listA', function(item) {
return item.update(1, function(item) {
item.selected = true;
return item;
});
});
问题是您在不可变列表中使用了 可变 值。对于列表,对象没有改变,因为 oldObject === newObject
仍然是 true.
这是一个简化的例子:
> var obj = {};
> var list = Immutable.List.of(obj);
> list2 = list.update(0, function(obj) { obj.foo = 42; return obj;});
> list2.get(0)
Object { foo: 42 }
> obj
Object { foo: 42 }
> list.get(0) === list2.get(0)
true
要解决此问题,除了还要更新地图(如果需要的话),您还必须
- 更新时克隆对象
- 使用地图而不是对象
- 在这种情况下可能最好:使用 record 而不是对象
示例:
var MyRecord = new Immutable.Record({id: null, name: '', selected: false});
var mapA = Immutable.fromJS({
listA: [
new MyRecord({
id: 1,
name: 'Name A'
}),
new MyRecord({
id: 2,
name: 'Name B'
})
]
});
var mapB = mapA.updateIn(['listA', 1], function(record) {
return record.set('selected', true);
});
console.log(mapB.get('listA') === mapA.get('listA')); // false
这是我的发现。问题是 List
,它基本上是普通 JavaScript 对象的集合。哪些是可变的。
解决方法很简单,我把初始对象创建改成这样
var mapA = Immutable.fromJS({
listA: [{
id: 1,
name: 'Name A',
selected: false
}, {
id: 2,
name: 'Name B',
selected: false
}]
});
现在,以下内容按预期工作。
var mapB = mapA.setIn(['listA', 1, 'selected'], true);