-
Notifications
You must be signed in to change notification settings - Fork 25
How is this any different from PureRenderMixin? #19
Comments
PureRenderMixin checks referential equality of plain js objects. This library uses Immutable data structures excel at referential comparison, there is no need to deeply check the diff on the objects; referential equality is guaranteed only if the objects are identical. |
This may be better than words... var user1 = {a: '1'};
var user2 = {a: '1'};
console.log('user1 === user2', user1 === user2); //false
user1.a = '2';
user2.a = '2';
console.log('user1 === user2', user1 === user2); //false
var iuser1 = Immutable.fromJS({a: '1'});
var iuser2 = Immutable.fromJS({a: '1'});
console.log('Immutable.is(iuser1, iuser2)', Immutable.is(iuser1, iuser2)); //true
console.log('iuser1 === iuser2', iuser1 === iuser2); //false
iuser1 = iuser1.set('a', '2');
iuser2 = iuser2.set('a', '2');
console.log('Immutable.is(iuser1, iuser2)', Immutable.is(iuser1, iuser2)); //true
console.log('iuser1 === iuser2', iuser1 === iuser2); //false |
Note: You can test the above on the console here: https://facebook.github.io/immutable-js/ |
closing please comment if this is still unclear |
Greetings @jurassix, First off, hope all is well and that Q1 2016 has treated you well. I understand your reasoning/explanation above regarding the use of The beauty of using Immutable data structures, as you stated above, is the fact that value equality effectively boils down to referential equality. Suppose you have a component which takes in an Immutable prop, like so...
... and, internally, this component implements shouldComponentUpdate using Further suppose, that a change in a parent component's state, say for example via a Redux store state change, causes a rerender down the component hierarchy which changes the the prop What am I missing? |
@natorojr Long time no talk! Hope all is well with you too. Firstly, I would agree with you that this library should not be needed, given the exact argument you sited about referential equality and shallowEquality. However, ~2 years ago when I was building out benchmarks using React and Immutable Data Structures, using PureRenderMixin didn't increase my performance. So I created this library, which was a direct copy of PureRenderMixin with a check to Immutable.is() added. Then plugged it into my app and saw a ~8x performance increase. I have spoken to @leebyron in the past and he expressed referential equality should work for Immutable Data Structures within React. Next Steps Prior Art |
Thanks for the quick response, explanation, and history, @jurassix Makes a lot of sense. I did some more research and experimentation into this topic (including poking around in the Immutable.js code and playing around with your benchmarks) and, as it turns out, unfortunately, my previous statement is not entirely true...
Although I believe that statement should be true in theory, it's not in practice/implementation of Immutable.js. From your code snippet above:
For some reason, I was under the impression that the last log line would return As such, I think there is definitely a purpose for this library. That said, one should be warned that Refer to: I guess the question becomes: What's faster? A complete re-render of the component hierarchy or a deep equality check of your props/state. Apparently, from your benchmarks, the later is definitely faster for a deeply nested HTML table. Any other thoughts/insights that might help me clarify my confusion? Best -NT |
I think this is illuminating... it looks like var o = {b: {a: '1'}};
var i = Immutable.fromJS(o);
var prev = i;
var b1 = i.get('b');
var b2 = i.get('b');
console.log('Immutable.is(b1, b2)', Immutable.is(b1, b2)); //true
console.log('b1 === b2', b1 === b2); //true
console.log('b1.get(a) === b2.get(a)', b1.get('a') === b2.get('a')); //true
i = i.setIn(['c'], '2');
console.log('i.getIn([b]) === prev.getIn([b])', i.getIn(['b']) === prev.getIn(['b'])); //true |
This issue in Immutable's repo may shed some light on this. Essentially, two different immutable objects that were created independently will never have referentially equality. So, it's not just From an example in that repo:
I'm not sure what the performance characteristics are of |
@dkingman Thanks for clearing up the root of the issue. Depending on your data structures and how deeply nested your components are it is probably better to do more processing in JavaScript than trying to re-render. Im my previous benchmarks my data structure was a multi-dimensional array, rendered as a 10,000 cell table. I would make a single cell update and render the entire tree from root. Immutable.is() optimization was way faster. Another facet of my testing was simulating data sets being pushed realtime to the client. If you are using a PATCH to update your client data, which would translate into set() and setIn() operations, then you should not break referential equality and PureRenderMixin would be fine. However, if you are serializing your application state, or a large part of it, over the wire and rendering from root then it's effectively like creating two equal maps, just not referentially equal and PureRenderMixin will not help. I think in general the school of thought is don't even use PureRenderMixin until you absolutely need it. React is super fast, and this is just another premature optimization that could expose a UI bug since we are halting rendering a child tree, etc. I think that goes doubly for this library, since their are two abstractions at play, React optimizations and Immutable data equality checks. So basically, if you need this you know you do. Like I did when I was barely able to update a 10,000 cell table using Vanilla React. I layered on PureRenderMixin, still no perf increases. Finally, I created a custom shouldComponentUpdate and got the perf I was after. Same thinking should help @natorojr decide if he needs to use this lib or not. In general, nope. |
Hi @jurassix. You use the phrase "referential integrity", but I don't think that's what you mean. This has a particular meaning in database systems (https://en.wikipedia.org/wiki/Referential_integrity). I haven't read the details of this issue, but perhaps you mean one of "referential equality", "value equality" or possibly "referential transparency". The problem is that I did a google search for the phrase "referential integrity immutable" as I was researching "referential integrity" (the database meaning) for immutable data, and this search result is very misleading. Because of React's popularity, this post shows up as the No.3 result. Could you please reword so this doesn't show up google results for "referential integrity"? The same goes for #6. Thanks. |
@mbylstra typo is now corrected. Sorry for the confusion. You were correct, 'referential equality' was my intent. |
Just to chime in here, I wouldn't personally advocate this, however there are two sorts of approaches to take:
Should you use this library instead of PureRenderMixin? By default no - but yes if it speeds things up for you in specific places. As was already pointed out, this library will use When would using this library be better than PureRenderMixin? If the values provided to your component repeatedly come from a source that's creating new Immutable.js collections. That should be relatively rare, but it definitely happens, and then this lib is exactly what you want. More typically though, you're using the Immutable.js methods like
Definitely! One of the most common culprits I find when investigating a codebase that uses Immutable.js and has performance issues is pervasive use of |
@leebyron Thanks for your insightful response and analysis of this thread! I think based on this issue alone, I should add warnings to the README persuading people to only use library as a last recourse. I can follow up that statement with some samples of best practices for Immutable.js and emphasize when this library could help them get the perf they are after, if these best practices haven't helped. |
Great idea! |
@leebyron : thanks for the info there. I've recently added several articles regarding use of Immutable.js and performance to my React/Redux links repo, and this fits in well. Your comment about use of I'll add your comment to that list shortly: https://github.com/markerikson/react-redux-links/blob/master/react-performance.md#immutable-data . |
@leebyron I've discovered my previous experimentations with Immutable and PureRenderMixin that ultimately led me to creating this library were erroneous. I've gone back to my performance tests and proved this library to be both slower and redundant. All, I've update the README to reflect that this library should not be needed and PureRenderMixin should be sufficient. Performance issues that are helped by this library are highlighting issues with the usage of Immutable. At this point I've frozen development of this library. One possible future is to convert this repo into a recipe book for usages of Immutable.js with React. Any help is appreciated. |
The docs don't really explain the difference between this library and PureRenderMixin. Could you clarify for me please?
The text was updated successfully, but these errors were encountered: