Skip to content
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

Element: Provide createHigherOrderComponent helper #5728

Merged
merged 2 commits into from
Apr 3, 2018
Merged

Conversation

aduth
Copy link
Member

@aduth aduth commented Mar 21, 2018

Context: #5206 (comment)

This pull request seeks to experiment with an alternative to @wordpress/element's getWrapperDisplayName function which is used to generate a display name for higher-order components. The use of this function is not always obvious, and can overcomplicate otherwise simple higher-order components by requiring the separate assignment of a class/function before then assigning displayName. The idea here is to eliminate consideration of the displayName with a generic helper for creating higher-order components, handling the assignment of the generated display name within the helper itself.

Implementation notes:

The code functionally works, though there are many other higher-order components we'd want to port if wanting to proceed, plus deprecating getWrapperDisplayName, or alternatively discouraging its use and leveraging it as the internal behavior of createHigherOrderComponent.

@aduth aduth added the Framework Issues related to broader framework topics, especially as it relates to javascript label Mar 21, 2018
@aduth aduth requested a review from gziolo March 21, 2018 13:53
element/index.js Outdated
return ( OriginalComponent ) => {
const EnhancedComponent = mapComponentToEnhancedComponent( OriginalComponent );
const { displayName = OriginalComponent.name || 'Component' } = OriginalComponent;
EnhancedComponent.displayName = `${ modifierName }(${ displayName })`;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We had upperFirst & camelCase on top of the modifier name to make sure it always looks like the name of the component. We may enforce it at the review time. Your call.

Copy link
Member

@gziolo gziolo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what we exactly what we discussed some time ago. I like this new HOC helper. We should refactor also all the existing occurrences and deprecate getWrapperDisplayName. We should also adjust the existing test for getWrapperDisplayName to work with the HOC or provide something similar. I can help with that tomorrow.

@gziolo
Copy link
Member

gziolo commented Mar 21, 2018

Yes, just wanted to say that I like how those HOCs evolve and make adding new functionalities easy to compose 💯

@gziolo
Copy link
Member

gziolo commented Mar 22, 2018

@aduth - I added the following changes with d9bbcf9:

  • Covered createHigherOrderComponent with unit tests.
  • Added deprecation for getWrapperDisplayName .
  • Refactored all occurences of getWrapperDisplayName with createHigherOrderComponent.

I tried to make this PR small so in some cases we might perform more refactorings, but I wanted to avoid too much noise to make the review process easier.

@gziolo gziolo changed the title Try: Element: Provide createHigherOrderComponent helper Element: Provide createHigherOrderComponent helper Mar 22, 2018
@gziolo
Copy link
Member

gziolo commented Mar 22, 2018

Something to think a bit more. I noticed that in many cases we define the same name for modifierName as the wrapping function. See:

export const withAlign = createHigherOrderComponent( ( BlockListBlock ) => {
	return ( props ) => {
		...
		return <BlockListBlock { ...props } wrapperProps={ wrapperProps } />;
	};
}, 'withAlign' );

I'm not sure if it is a good idea, but we might want to make the modifierName optional. In such case, we could take it directly from the wrapper function's name. Something to think about, as a further improvement. It might be also confusing and error-prone.

return ( OriginalComponent ) => {
const EnhancedComponent = mapComponentToEnhancedComponent( OriginalComponent );
const { displayName = OriginalComponent.name || 'Component' } = OriginalComponent;
EnhancedComponent.displayName = `${ upperFirst( camelCase( modifierName ) ) }(${ displayName })`;
Copy link
Member

@gziolo gziolo Mar 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I replicated the old behavior upperFirst( camelCase( modifierName ) ) when porting old tests - feel free to update if you think it's not necessary.

@@ -141,7 +141,7 @@ function gutenberg_register_scripts_and_styles() {
wp_register_script(
'wp-element',
gutenberg_url( 'element/build/index.js' ),
array( 'react', 'react-dom', 'react-dom-server' ),
array( 'react', 'react-dom', 'react-dom-server', 'wp-utils' ),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope it's temporary until we remove deprecated function :)

@gziolo gziolo requested a review from a team March 30, 2018 09:53
@gziolo gziolo added this to the 2.6 milestone Mar 30, 2018
Copy link
Contributor

@mcsf mcsf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pending my observations, LGTM

return WrappedComponent;
};
};
} );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing 'withState' as modifierName.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(amended & pushed)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks 👍

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see amend?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh. Maybe it got nuked in a subsequent rebase, @gziolo?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I did something wrong :(
Do you have this branch locally with your commit?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I did something wrong

My fault for rebasing your commit. ;)

Do you have this branch locally?

I do, the rebase is 0ae3d2 and the fix is e3a846.

Copy link
Member

@gziolo gziolo Apr 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with 66b2268, thanks!

*
* @return {WPComponent} Component class with generated display name assigned.
*/
export function createHigherOrderComponent( mapComponentToEnhancedComponent, modifierName ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we don't attempt to infer modiferName, should there be a warning if the argument is missing?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would leave it for reviewers for the time being. It seems to be a really great strategy 😃

In the next iteration, I would prefer to introduce the attempt infer this name and warn when it fails.

@mcsf mcsf force-pushed the add/create-hoc branch from aaa0aad to 0ae3d2a Compare April 2, 2018 18:06
@gziolo gziolo merged commit 41fa06a into master Apr 3, 2018
@gziolo gziolo deleted the add/create-hoc branch April 3, 2018 09:36
@aduth
Copy link
Member Author

aduth commented Apr 4, 2018

In such case, we could take it directly from the wrapper function's name. Something to think about, as a further improvement. It might be also confusing and error-prone.

Perhaps. I expect this wouldn't work so well for minified code (related: Automattic/wp-calypso#18650 ). Whether we care about this is another question, as we're not really using the name in runtime environments except maybe React DevTools.

@gziolo
Copy link
Member

gziolo commented Apr 4, 2018

You can instrument uglify to preserve function names, but still it might not always work. It seems to be okay as it is in that context.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Framework Issues related to broader framework topics, especially as it relates to javascript
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants