Try adding a pure Higher Order Component#6313
Conversation
33c838e to
1f428d3
Compare
|
Would using |
|
@atimmer Not certain what's the difference between the two implementation, do you know more about it? I kind of like the HoC approach, where you can use it without transforming your component into a class. Also, I don't think it's possible to use React.PureComponent the way I'm implementing |
|
From https://reactjs.org/docs/react-api.html#reactpurecomponent:
Indeed it's interesting how you handle
Not sure about this part. I would expect children components to re-render when they are wrapped with data HOCs anyway. |
|
@youknowriad can we add some tests once we agree that it is the way to go to make sure that |
|
Minor: have you considered naming it
|
|
I generally approve this. I agree tests, esp. for regressions, are in order. Further: although making some critical components pure should help us a lot, there's the caveat that this HoC may be abused in the future if not applied judiciously (like other kinds of premature or uninformed optimization). Short of improving HoC documentation, I don't really know what the solution for that is. :) |
| * @return {Component} Enhanced component with merged state data props. | ||
| */ | ||
| export const withSelect = ( mapStateToProps ) => createHigherOrderComponent( ( WrappedComponent ) => { | ||
| return class ComponentWithSelect extends Component { |
There was a problem hiding this comment.
Can this be expressed as:
createHigherOrderComponent( compose( [
purify,
( WrappedComponent ) => class extends Component {
}
] ), 'withSelect' );
element/index.js
Outdated
| * | ||
| * @return {WPComponent} Component class with generated display name assigned. | ||
| */ | ||
| export const purify = createHigherOrderComponent( ( Wrapped ) => { |
There was a problem hiding this comment.
Why did you choose to export this in element, and not components ?
FWIW, I had a branch with similar change, and encountered that data would then depend on components, which surfaced yet another issue of: Should withSelect and withDispatch be in data or not?
There was a problem hiding this comment.
I asked myself several times about withFilters in components which depends on hooks. A very similar case.
Why did you choose to export this in element, and not components ?
I'm sure this is all about dependencies. There needs to be a solution :)
There was a problem hiding this comment.
I actually didn't think that much about it. I put it under element to match React :) which also provides a pure component definition.
There was a problem hiding this comment.
Hmm, ignoring the fact that React does it, I don't see why, for example, we'd want to export a pure higher-order component in element, but ifCondition higher-order component in components. What judgement do we use to categorize them?
There was a problem hiding this comment.
pure, ifCondition, withState, withInstanceId, but also createHigherOrderComponent and compose - we can put all of them together in their own module 💯
There was a problem hiding this comment.
The alternative perspective is that components is a baseline, and where we're encountering circular dependencies is a sign where we have our dependencies inversed. Considering viewport and the issues highlighted in #5316, the current dependency hierarchy is:
Viewport (
ifViewportMatches) > Components (ifCondition)
(This is problematic in #5316 in introducing the reverse dependency from Popover to Viewport)
Where maybe it ought to be:
Components (
ifViewportMatches+ifCondition) > Viewport (withSelect( 'viewport' ))
This highlights a third type of component: Data-bound components.
We could treat them all separately, e.g. higher-order-components, app-components, ui-components, though it's not clear to me whether this will ultimately solve all of our issues, and of course has added overhead in making determinations of which components / utilities belong where.
There was a problem hiding this comment.
So did we just not decide anything here?
There was a problem hiding this comment.
I assumed it's going to be renamed to pure.
There was a problem hiding this comment.
It was ... I guess you are referring to the location of this HOC, we need to come up with something sooner than later 👍
|
|
||
| return class extends Component { | ||
| shouldComponentUpdate( nextProps ) { | ||
| return ! isShallowEqual( nextProps, this.props ); |
There was a problem hiding this comment.
Interesting conclusion that we don't need to compare state here, and I suppose it makes sense since it's wrapping the original (non-class) component.
There was a problem hiding this comment.
Agreed on this one, there is no state in functional components 👍
element/test/index.js
Outdated
There was a problem hiding this comment.
Typo in the comment (also in line 246).
How this wrapper.update() works, it's super confusing ...
There was a problem hiding this comment.
Well I wanted to rerender the component without passing new props or something. But it's not that important since passing a similar prop is also tested
f2f471e to
67e17f6
Compare
|
I would love to see this PR merged later this week. I guess the only remaining issue is where this new functionality should be located as discussed here: #6313 (comment). Otherwise, it has big 👍 from me :) |
|
I've published |
|
@aduth Are you planning to update this PR or use |
|
@youknowriad In the process of integrating, I found a bug which led to WordPress/packages#116 . We could merge that and bring it in here, or do separately. I'd be fine to do separately as well. |
This PR adds a purify Higher Order Component used to wrap
withSelectandwithDispatchcomponents (for now) to make them pure.Pure components mean they don't rerender unless their props or state changed (shallow equality).
Testing instructions
Notes