-
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
Soft deprecate custom 'pure' HoC in favor of 'React.memo' #57173
Conversation
Size Change: +7 B (0%) Total Size: 1.7 MB
ℹ️ View Unchanged
|
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.
Can we update the HoC to use pure
and deprecate it?
Do you mean to update our custom HoC to use Yes, I was thinking the same. There are a few more usages of |
Sure, why not? Don't see the point of just updating one instance? |
Makes sense. I'll make the remaining changes tomorrow morning. |
This comment was marked as outdated.
This comment was marked as outdated.
dd0b0ac
to
df2f93c
Compare
cc @WordPress/native-mobile |
Hey @Mamaduka, I can take a look at the changes and see how they impact the native mobile version. I see that both mobile E2E and unit tests are failing, so it's likely that we need to tweak some parts of the native files. I'll share more information once I investigate it. Thanks 🙇 ! |
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 is great, thanks @Mamaduka! One fewer feature to maintain!
@@ -141,6 +141,8 @@ _Related_ | |||
|
|||
### pure | |||
|
|||
> **Deprecated** Use `memo` or `PureComponent` instead. |
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.
Should we make it clear that memo
is from @wordpress/element
or react
?
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.
I can't find the issue, but I remember there was a talk of allowing imports from react
. So folks can decide that for themself.
@@ -141,6 +141,8 @@ _Related_ | |||
|
|||
### pure | |||
|
|||
> **Deprecated** Use `memo` or `PureComponent` instead. |
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.
Also, we don't expose PureComponent
at all in @wordpress/element
, do we? So it can be confusing to mention it in the first place.
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 only reason the PureComponent
was omitted was because of this HoC. See #33674 (comment).
@@ -17,10 +18,17 @@ import { createHigherOrderComponent } from '../../utils/create-higher-order-comp | |||
/** | |||
* Given a component returns the enhanced component augmented with a component | |||
* only re-rendering when its props/state change | |||
* | |||
* @deprecated Use `memo` or `PureComponent` instead. |
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.
Same as above.
*/ | ||
const pure = createHigherOrderComponent( function < Props extends {} >( | ||
WrappedComponent: ComponentType< Props > | ||
): ComponentType< Props > { | ||
deprecated( 'wp.compose.pure', { | ||
since: '6.5', | ||
alternative: 'Use `memo` or `PureComponent` instead', |
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.
Same as above.
pure( ( ownProps ) => { | ||
memo( ( ownProps ) => { |
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.
@Mamaduka After testing the mobile native version, I noticed a nuance here. When using memo
, if I try to get the reference via the ref
prop in the resulting component, I get the following warning:
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
I explored further and realized that the difference between using pure
and memo
is that each returns different types:
pure
returns class component.memo
returns function component.
For the latter, I can't use forwardRef
anymore for forwarding the ref after using withSelect
. I wonder if we should implement a mechanism for this. WDYT?
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.
Thanks for looking into this, @fluiddot!
Can you link me to one of these components? I would like to experiment a bit with ideas.
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.
Sure, the component that was failing is this one which is used here. Note that both are only used in the mobile native version, so you'd need to run the demo app to test it.
In any case, since the issue is not only affecting the mobile native version, I'd recommend tweaking the code with a test component for testing. I took the liberty to generate the following patch file as a demonstration of the issue:
diff --git forkSrcPrefix/packages/edit-post/src/components/visual-editor/index.js forkDstPrefix/packages/edit-post/src/components/visual-editor/index.js
index fd9b4a6ff8bb6cc7d4ba5145bc7928259f18a33a..82cd77a5b039d5ce50d6f5503d39df2f7d4ba63d 100644
--- forkSrcPrefix/packages/edit-post/src/components/visual-editor/index.js
+++ forkDstPrefix/packages/edit-post/src/components/visual-editor/index.js
@@ -10,8 +10,8 @@ import {
store as editorStore,
privateApis as editorPrivateApis,
} from '@wordpress/editor';
-import { useMemo } from '@wordpress/element';
-import { useSelect } from '@wordpress/data';
+import { useMemo, Component } from '@wordpress/element';
+import { useSelect, withSelect } from '@wordpress/data';
import { store as blocksStore } from '@wordpress/blocks';
/**
@@ -24,6 +24,13 @@ const { EditorCanvas } = unlock( editorPrivateApis );
const isGutenbergPlugin = process.env.IS_GUTENBERG_PLUGIN ? true : false;
+class ClassComponent extends Component {
+ render() {
+ return null;
+ }
+}
+const ClassComponentWithSelect = withSelect( () => ( {} ) )( ClassComponent );
+
export default function VisualEditor( { styles } ) {
const {
isWelcomeGuideVisible,
@@ -83,6 +90,10 @@ export default function VisualEditor( { styles } ) {
'has-inline-canvas': ! isToBeIframed,
} ) }
>
+ { /* This works */ }
+ <ClassComponent ref={ () => {} } />
+ { /* This produces a warning. */ }
+ <ClassComponentWithSelect ref={ () => {} } />
<EditorCanvas
disableIframe={ ! isToBeIframed }
styles={ styles }
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.
We should deprecate withSelect too :P
Flaky tests detected in 0939b95. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/7299927486
|
I am currently considering soft-deprecating This way we can maintain backward compatibility for hooks like What do you think? |
@@ -55,7 +55,7 @@ function ScaledBlockPreview( { | |||
}, [ styles, additionalStyles ] ); | |||
|
|||
// Initialize on render instead of module top level, to avoid circular dependency issues. | |||
MemoizedBlockList = MemoizedBlockList || pure( BlockList ); | |||
MemoizedBlockList = MemoizedBlockList || memo( BlockList ); |
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.
Hm, this feels super weird! Does this even work? :D
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.
I think so 😅 there is even a Babel plugin that applies similar optimizations - https://babeljs.io/docs/babel-plugin-transform-react-constant-elements.html
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 was marked as an error
by the new eslint-plugin-react-compiler
plugin - https://github.com/WordPress/gutenberg/actions/runs/9158471368/job/25176908344?pr=61788#step:5:86.
@@ -74,6 +84,9 @@ describe( 'pure', () => { | |||
); | |||
|
|||
const { rerender } = render( <MyComp /> ); | |||
expect( console ).toHaveWarnedWith( | |||
'wp.compose.pure is deprecated since version 6.5. Please use Use `memo` or `PureComponent` instead instead.' |
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.
What is PureComponent?
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.
0939b95
to
044154f
Compare
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.
Looks good to me, thanks! 👍
Left a couple of minor comments, nothing blocking.
I also wanted to ask if we're intentionally leaving the pure()
usage for:
withSelect
: https://github.com/WordPress/gutenberg/blob/try/block-support-replace-pure-with-memo/packages/data/src/components/with-select/index.js#L56withViewportMatch
: https://github.com/WordPress/gutenberg/blob/try/block-support-replace-pure-with-memo/packages/viewport/src/with-viewport-match.js#L51
Yes, to avoid making this a breaking change. See #57173 (comment) and #57173 (comment). |
What?
Requires: #57193.
PR replaces
pure
usage withReact.memo
where possible and soft deprecates the custom HoC.Why?
I think the core custom HoC pre-dates
React.memo
and maybe evenPureComponent
. Using APIs provided by React has the benefit of inheriting all optimizations that the library might ship in the future.Testing Instructions