13

I have 2 nested structures newState and newState1.

But when I compare their, equals() or Immutable.is() returned false. The values in these structures identical.

How to correctly compare newState and newState1?

var grid = {
    editable: false,
    widgets: [{
        name: 'Some widget',
        type: 'List',
        defaultDataSource: 'daily',
        dataSources: {}
    }, {
        name: 'Some widget1',
        type: 'List',
        defaultDataSource: 'daily',
        dataSources: {}
    }]
};

var state = Immutable.fromJS(grid);

var newState = state.updateIn(['widgets'], function (list) {
    return list.push(Immutable.Map({
        name: 'Some widget2',
        type: 'List',
        defaultDataSource: 'daily',
        dataSources: {}
    }));
});

var newState1 = state.updateIn(['widgets'], function (list) {
    return list.push(Immutable.Map({
        name: 'Some widget2',
        type: 'List',
        defaultDataSource: 'daily',
        dataSources: {}
    }));
});

console.log(state.toJS(), newState.toJS(), newState1.toJS());

console.log(newState.equals(newState1)); //false

Code in JSFiddle: https://jsfiddle.net/z3xuagwm/

Slava Minchonok
  • 141
  • 1
  • 1
  • 7
  • `dataSources` is an javascript object, and not converted to Immutable ones. [change it to string ver.](https://jsfiddle.net/z3xuagwm/2/). Or if you [update with map](https://jsfiddle.net/z3xuagwm/3/). – fuyushimoya Oct 02 '15 at 18:40

3 Answers3

20

It seems that immutablejs don't do deep conversion, so if your value is object, it stays to be object.

As you're creating different object in each update step, and those objects will be treat different when you compare to each other, so you should also convert it to Immutable.Map object, to make the compare be true.

// Primitives.
var test1 = Immutable.Map({
    a: 'a', 
    b: 'b', 
    c: 'c'
});
var test2 = Immutable.Map({
    a: 'a',
    b: 'b',
    c: 'c'
});
console.log('Test primitive', test1.equals(test2)); // true

// Object
test1 = Immutable.Map({
    a: 'a',
    b: 'b',
    c: {}
});
test2 = Immutable.Map({
    a: 'a',
    b: 'b',
    c: {}
});
console.log('Test object', test1.equals(test2));  // false
// Its because
var a = {};
var b = {};
console.log('a === b?', a === b); // false

// Convert
test1 = Immutable.Map({
    a: 'a',
    b: 'b',
    c: Immutable.Map({})
});
test2 = Immutable.Map({
    a: 'a',
    b: 'b',
    c: Immutable.Map({})
});
console.log('Test converted', test1.equals(test2)); // true
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.7.5/immutable.min.js"></script>
fuyushimoya
  • 9,715
  • 3
  • 27
  • 34
10

Change Immutable.Map to Immutable.fromJS in your push functions (as has been mentioned - only fromJS will do a deep conversion, Map,List etc won't):

var newState = state.updateIn(['widgets'], function (list) {
    return list.push(Immutable.fromJS({
        name: 'Some widget2',
        type: 'List',
        defaultDataSource: 'daily',
        dataSources: {}
    }));
});

var newState1 = state.updateIn(['widgets'], function (list) {
    return list.push(Immutable.fromJS({
        name: 'Some widget2',
        type: 'List',
        defaultDataSource: 'daily',
        dataSources: {}
    }));
});
-2

What about using JSON.stringify?

JSON.stringify(values) !== JSON.stringify(anothervalue);

If you know they are not circular objects, and do not contain functions, I think it's the fastest way to compare them.

Tushar
  • 85,780
  • 21
  • 159
  • 179
kompupat
  • 15
  • 2
  • That doesn't always work because two JSON objects with the same properties will not always look the same. There is a module, `json-is-equal`, that can work for you, https://github.com/Kikobeats/json-is-equal – freeall Jan 23 '17 at 10:43
  • it will work when you are muting obj1 into obj2, then the order of properties is always the same. if it is not, then the object has been muted for sure, so the test is valid. comparing 2 immutable objects, where the second one was not created as a mutation of the first one, should always be false from the definition I think – kompupat Jan 25 '17 at 11:51
  • 1
    Sure, in the case where you have 100% control and understand that your javascript implementation will not changed the order of the properties, then yes. I don't think I've ever been sure of that, and I don't think that's a guarantee that any implementation makes. I might be wrong though. – freeall Mar 23 '17 at 19:40
  • a) There's no guarantee of ordering of entries in a map or is stringified form - just because it works for you in your environment doesn't mean it will work any other environment. – Jelaby Sep 08 '17 at 09:00
  • (ran out of edit time) b) taking an object and building a string out of it is not going to be fast at runtime, mainly because you now have to build and parse the Json on every write *and read* but also if your comparisons are usually negative, a short-circuiting comparison will likely be faster on average however fast stringifying is. – Jelaby Sep 08 '17 at 09:16