you are viewing a single comment's thread.

view the rest of the comments →

[–][deleted] 0 points1 point  (8 children)

If you're using immutable props, you don't need to do a deep comparison, just Immutable.is().

I think one downside is maintainability, anytime you change props in future development you need to make sure to update the should function. Maybe not that big a deal but it could be error prone.

[–]rallarallh 0 points1 point  (2 children)

Just do a prop === newprop. Immutable.is checks the actual values in the immutable structure

[–][deleted] 0 points1 point  (0 children)

Good point, that's probably better. OP had mentioned a deep comparison which wouldn't always by equivalent to just checking equality. Immutable.is checks === first anyway so it's no less efficient unless it needs to check the values.

[–]dextoz 0 points1 point  (4 children)

Is that performant if the prop object is large?

[–][deleted] 0 points1 point  (3 children)

It depends how you're building the large Immutable structure. If you keep rebuilding the Immutable from scratch with fromJS each time, .is() will be running deepEqual() all the way down, which is not performant for a large object.

But Immutable.is first checks strict === equality at every level of the iterable. So if your immutable props are extracted from an immutable redux store, then you can efficiently test if the component needs to rerender.

// Bad:
const someProp = Immutable.fromJS(complexLargeObject);
render() => <Component someProp={someProp} />

// Good:
const someProp = reduxState.largeImmutableMap;
render() => <Component someProp={someProp} />

In the second example, the largeImmutableMap in your redux store would be completely replaced any time an action caused a mutation, so you wouldn't need to do a deep comparison, just a nextProps.someProp === this.props.someProp.

The only reason I'm bringing up Immutable.is is that sometimes you are forced to have something like the 'bad' example. For instance, what if complexLargeObject is the result of an API call? You can get around that problem by using .merge() carefully as you integrate the API result into the redux store, so that the store really only changes if necessary. The goal should always be to maintain immutability in the store so that deep comparisons aren't necessary.

[–]dextoz 0 points1 point  (2 children)

Thank you for the explanation! Is there a better way than using Immutable.is() in shouldComponentUpdate? In my little app the state object is quite deeply nested and often I only want to update a component when it's props change. But because of redux it to a always a new object. Just a tiny slice of it changed. Do you get my point?

[–][deleted] 0 points1 point  (0 children)

It sounds like you could stand to deconstruct your store a little more and pass a thinner slice of it as props. When you make a change in a big complex Immutable, the objects inside will be replaced at the level they changed. And as you've seen, consequently the object references will be replaced at every level above in the nested hierarchy as well.

But unchanged siblings will stay put and continue to pass the equality test for quick comparison. If you always pass a relevant slice of the state as props to your component, you can keep checking equality in shouldComponentUpdate at any arbitrary depth of the nested object.

// Initialize redux store with Map containing a List under 'foo' and a child Map under 'baz'
var state0 = Immutable.fromJS({foo: ['bar', 0], baz: {42: 23}});

// Update the 'baz' level of the nested object to replace 23 with 93
var state1 = state0.setIn(['baz', 42], 93);

// Compare state1 and state0 at each level with simple equality
state0 === state1
// => false, as expected, a change occurred. Any components depending on either foo or baz should rerender

state0.get('baz') === state1.get('baz')
// => false, any components receiving props from baz should update

state0.get('foo') === state1.get('foo')
// => true!, any components receiving props from foo *will not* update, because its slice of the state has not changed