How to update an immutable list to get a new list

I have an immutable Map next

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

I want to update the selected key in the list. According to immutable.js docs for list.update .

Returns a new list with the updated value in the index, returning the value of the calling update

However, if I do this

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

and, check the equality of the object, it gives me true .

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

What am I doing wrong here? Doesn't that mean immutable.js should work?

+6
source share
3 answers

The problem is that you are using a mutable variable inside an immutable list. The object does not change for the list, since oldObject === newObject is still true.

Here is a simplified example:

 > 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 

To solve this problem, besides updating the map (if you want it), you need to either

  • Clone an object when updating
  • Use map instead of object
  • Probably best in this case: write instead of object

Example:

 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 
+1
source

You will also need to update the map.

 var mapB = mapA.update('listA', function(item) { return item.update(1, function(item) { item.selected = true; return item; }); }); 
+3
source

Here is what I found. The problem is List , it is basically a collection of simple JavaScript objects. Which are mutable.

The solution is simple, I changed its original creation.

 var mapA = Immutable.fromJS({ listA: [{ id: 1, name: 'Name A', selected: false }, { id: 2, name: 'Name B', selected: false }] }); 

and now, as expected, it works.

 var mapB = mapA.setIn(['listA', 1, 'selected'], true); 
0
source

All Articles