-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Data: Optimize withSelect to avoid generating merge props on equal props #7699
Conversation
While this is likely a valid optimization, in some testing this is still not even close to the same level of performance. Typing in the demo post, for example, is unbearably slow, even after these changes, when contrasted with the variation of |
This approach turned out to be much more viable, and made a night-and-day difference to the usability of the demo post. I'm still not entirely clear what was problematic about the previous implementation: It may be that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The last iteration of this PR makes a huge difference for me when editing the demo post.
I'd have a second set of eyes on this, but it looks like solid work. Yes, concessions are made, but this is quite the hot path.
@@ -529,6 +529,64 @@ describe( 'withSelect', () => { | |||
expect( OriginalComponent ).toHaveBeenCalledTimes( 2 ); | |||
} ); | |||
|
|||
it( 'should not run selection if props have not changed', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one fails in master
because mapSelectToProps
gets called twice. This is a very good indicator that this PR fixes the issue.
*/ | ||
function getNextMergeProps( props ) { | ||
return ( | ||
mapStateToProps( select, props ) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unrelated: we should rename mapStateToProps
to mapSelectToProps
.
Yes, I can confirm that it works much better. I was able to confirm that we don't notice double re-renders anymore in both testing and when comparing with the |
Closes #7680
Closes #6466
Closes #7498
This pull request seeks to implement the data module's
withSelect
implementation to avoid a case wheremapSelectToProps
would be called wastefully when neither the state had triggered a change nor had incoming props changed (as a product of shallow equality comparison).This had been effected in previous implementations leveraging
componentWillReceiveProps
, but was lost in the upgrade to usingstatic getDerivedStateFromProps
:gutenberg/packages/data/src/index.js
Lines 300 to 301 in 95ef796
It required some refactoring to account for state changes made by the artificial trigger from the component's subscription, to handle generating new merge props on either a state change or incoming props change, while ensuring that the component only re-renders when either props or merge props are shallowly unequal, also ensuring that
isShallowEqual
is called at most one time per props sets during this render pass.In future iterations, it may be worth exploring to see whether
props
andfromStoreUpdate
can be omitted from state. I'd considered assigning instance variables inshouldComponentUpdate
and the subscription callback, where in the latter we'd callforceUpdate
to skipshouldComponentUpdate
. The main downside to this is thatshouldComponentUpdate
should ideally not have side effects such as assigning instance variables.Testing instructions:
Ensure new unit tests pass:
Observe lag or CPU usage differences from this branch in contrast with master.