Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update immutable List to get a new List

I have an immutable Map like the following

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 key selected within the list. As per immutable.js docs for list.update.

Returns a new List with an updated value at index with the return value of calling updater

However, if I do this

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

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

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

What am I doing wrong here? Isn't that how immutable.js is supposed to work?

like image 216
Salman Avatar asked Sep 20 '15 04:09

Salman


2 Answers

You'd need to update the Map too.

var mapB = mapA.update('listA', function(item) {
    return item.update(1, function(item) {
        item.selected = true;
        return item;
    });
});
like image 63
Dan D. Avatar answered Sep 21 '22 10:09

Dan D.


The problem is that you are using a mutable value inside an immutable list. For the list, the object doesn't change, because 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, in addition to also update the map (if you want that), you have to either

  • Clone the object on update
  • Use a Map instead of an object
  • Probably best in this case: Use a record instead of an 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
like image 43
Felix Kling Avatar answered Sep 23 '22 10:09

Felix Kling