From e9e00d4f9b578680981e336857af925d654eaaeb Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Thu, 3 Oct 2024 11:03:26 +0200 Subject: [PATCH] Try: Use `createSelector` --- .../block-editor/src/hooks/block-bindings.js | 25 +++--- packages/editor/src/bindings/post-meta.js | 79 +++++++++++-------- 2 files changed, 63 insertions(+), 41 deletions(-) diff --git a/packages/block-editor/src/hooks/block-bindings.js b/packages/block-editor/src/hooks/block-bindings.js index cf7871fab6367d..ad6211bdfbc782 100644 --- a/packages/block-editor/src/hooks/block-bindings.js +++ b/packages/block-editor/src/hooks/block-bindings.js @@ -205,6 +205,8 @@ export const BlockBindingsPanel = ( { name: blockName, metadata } ) => { * whenever there are updates in block context. * `source.getFieldsList` may also call a selector via `registry.select`. */ + // A constant object needs to be used to avoid unnecessary re-renders. + const context = {}; const fieldsList = useSelect( ( select ) => { if ( ! bindableAttributes || bindableAttributes.length === 0 ) { @@ -216,26 +218,24 @@ export const BlockBindingsPanel = ( { name: blockName, metadata } ) => { ( [ sourceName, { getFieldsList, usesContext } ] ) => { if ( getFieldsList ) { // Populate context. - const context = {}; if ( usesContext?.length ) { for ( const key of usesContext ) { context[ key ] = blockContext[ key ]; } } - const sourceList = getFieldsList( { + _fieldsList[ sourceName ] = getFieldsList( { select, context, } ); - // Only add source if the list is not empty. - if ( Object.keys( sourceList || {} ).length ) { - _fieldsList[ sourceName ] = { ...sourceList }; - } + + // Clean `context` variable for next iterations. + Object.keys( context ).forEach( ( key ) => { + delete context[ key ]; + } ); } } ); - return ( - Object.values( _fieldsList ).length > 0 && { ..._fieldsList } - ); + return _fieldsList; }, [ blockContext, bindableAttributes ] ); @@ -255,6 +255,13 @@ export const BlockBindingsPanel = ( { name: blockName, metadata } ) => { } } ); + // Remove empty sources from the list of fields. + Object.entries( fieldsList || {} ).forEach( ( [ key, value ] ) => { + if ( ! Object.keys( value || {} ).length ) { + delete fieldsList[ key ]; + } + } ); + // Lock the UI when the user can't update bindings or there are no fields to connect to. const readOnly = ! canUpdateBlockBindings || ! Object.keys( fieldsList || {} ).length; diff --git a/packages/editor/src/bindings/post-meta.js b/packages/editor/src/bindings/post-meta.js index 9198ac0fe41e1e..1b48739cbec663 100644 --- a/packages/editor/src/bindings/post-meta.js +++ b/packages/editor/src/bindings/post-meta.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { store as coreDataStore } from '@wordpress/core-data'; +import { createSelector } from '@wordpress/data'; /** * Internal dependencies @@ -34,42 +35,56 @@ import { unlock } from '../lock-unlock'; * } * ``` */ -function getPostMetaFields( select, context ) { - const { getEditedEntityRecord } = select( coreDataStore ); - const { getRegisteredPostMeta } = unlock( select( coreDataStore ) ); +const getPostMetaFields = createSelector( + ( select, context ) => { + const { getEditedEntityRecord } = select( coreDataStore ); + const { getRegisteredPostMeta } = unlock( select( coreDataStore ) ); - let entityMetaValues; - // Try to get the current entity meta values. - if ( context?.postType && context?.postId ) { - entityMetaValues = getEditedEntityRecord( - 'postType', - context?.postType, - context?.postId - ).meta; - } - - const registeredFields = getRegisteredPostMeta( context?.postType ); - const metaFields = {}; - Object.entries( registeredFields || {} ).forEach( ( [ key, props ] ) => { - // Don't include footnotes or private fields. - if ( key !== 'footnotes' && key.charAt( 0 ) !== '_' ) { - metaFields[ key ] = { - label: props.title || key, - value: - // When using the entity value, an empty string IS a valid value. - entityMetaValues?.[ key ] ?? - // When using the default, an empty string IS NOT a valid value. - ( props.default || undefined ), - }; + let entityMetaValues; + // Try to get the current entity meta values. + if ( context?.postType && context?.postId ) { + entityMetaValues = getEditedEntityRecord( + 'postType', + context?.postType, + context?.postId + ).meta; } - } ); - if ( ! Object.keys( metaFields || {} ).length ) { - return null; - } + const registeredFields = getRegisteredPostMeta( context?.postType ); + const metaFields = {}; + Object.entries( registeredFields || {} ).forEach( + ( [ key, props ] ) => { + // Don't include footnotes or private fields. + if ( key !== 'footnotes' && key.charAt( 0 ) !== '_' ) { + metaFields[ key ] = { + label: props.title || key, + value: + // When using the entity value, an empty string IS a valid value. + entityMetaValues?.[ key ] ?? + // When using the default, an empty string IS NOT a valid value. + ( props.default || undefined ), + }; + } + } + ); - return metaFields; -} + if ( ! Object.keys( metaFields || {} ).length ) { + return null; + } + + return metaFields; + }, + ( select, context ) => [ + select( coreDataStore ).getEditedEntityRecord( + 'postType', + context.postType, + context.postId + ).meta, + unlock( select( coreDataStore ) ).getRegisteredPostMeta( + context.postType + ), + ] +); export default { name: 'core/post-meta',