如何更新不可变列表以获得新列表

How to update immutable List to get a new List

本文关键字:列表 新列表 不可变 何更新 更新      更新时间:2023-09-26

我有一个不可变的Map,就像下面的

var mapA = Map({
  listA: List.of({
    id: 1,
    name: 'Name A',
    selected: false
  }, {
    id: 2,
    name: 'Name B',
    selected: false
  })
});

我想更新列表中的密钥selected。根据list.update的immutable.js文档。

返回一个新列表,该列表在索引处具有更新的值调用更新程序的值

但是,如果我这样做

var listB = mapA.get('listA').update(1, function (item) {
    item.selected = true;
    return item;
});

并且,检查对象的相等性,它给了我true

console.log(listB === x.get('listA')); // true

我在这里做错了什么?immutable.js不就是这样工作的吗?

您还需要更新Map。

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

为了解决这个问题,除了更新地图(如果你想的话(,你还必须使用

  • 更新时克隆对象
  • 使用贴图而不是对象
  • 在这种情况下可能最好:使用记录而不是对象

示例:

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);