From bf163d426b8b1424cc7ddcda0f5e51da86c809c9 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Mon, 19 Jun 2023 14:43:08 +1000 Subject: [PATCH] Prevent BlockBreadcrumb from re-rendering unnecessarily when typing --- .../src/components/block-breadcrumb/index.js | 8 +- .../src/store/private-selectors.js | 26 +++++ .../src/store/test/private-selectors.js | 96 +++++++++++++++++++ 3 files changed, 124 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/components/block-breadcrumb/index.js b/packages/block-editor/src/components/block-breadcrumb/index.js index 9e4ab5391d8c4..13cc93d41a981 100644 --- a/packages/block-editor/src/components/block-breadcrumb/index.js +++ b/packages/block-editor/src/components/block-breadcrumb/index.js @@ -26,15 +26,11 @@ function BlockBreadcrumb( { rootLabelText } ) { const { getSelectionStart, getSelectedBlockClientId, - getBlockParents, - getBlockEditingMode, + getEnabledBlockParents, } = unlock( select( blockEditorStore ) ); const selectedBlockClientId = getSelectedBlockClientId(); return { - parents: getBlockParents( selectedBlockClientId ).filter( - ( parentClientId ) => - getBlockEditingMode( parentClientId ) !== 'disabled' - ), + parents: getEnabledBlockParents( selectedBlockClientId ), clientId: selectedBlockClientId, hasSelection: !! getSelectionStart().clientId, }; diff --git a/packages/block-editor/src/store/private-selectors.js b/packages/block-editor/src/store/private-selectors.js index c250b649569f0..1eff2e8510dcc 100644 --- a/packages/block-editor/src/store/private-selectors.js +++ b/packages/block-editor/src/store/private-selectors.js @@ -17,6 +17,7 @@ import { getTemplateLock, getBlockName, getBlockOrder, + getBlockParents, } from './selectors'; /** @@ -169,3 +170,28 @@ export const getListViewClientIdsTree = createSelector( state.blockListSettings, ] ); + +/** + * Returns a list of a given block's ancestors, from top to bottom. Blocks with + * a 'disabled' editing mode are excluded. + * + * @see getBlockParents + * + * @param {Object} state Global application state. + * @param {string} clientId The block client ID. + * @param {boolean} ascending Order results from bottom to top (true) or top + * to bottom (false). + */ +export const getEnabledBlockParents = createSelector( + ( state, clientId, ascending = false ) => { + return getBlockParents( state, clientId, ascending ).filter( + ( parent ) => getBlockEditingMode( state, parent ) !== 'disabled' + ); + }, + ( state ) => [ + state.blocks.parents, + state.blockEditingModes, + state.settings.templateLock, + state.blockListSettings, + ] +); diff --git a/packages/block-editor/src/store/test/private-selectors.js b/packages/block-editor/src/store/test/private-selectors.js index ab0d4b11c5bf4..30cf702c60526 100644 --- a/packages/block-editor/src/store/test/private-selectors.js +++ b/packages/block-editor/src/store/test/private-selectors.js @@ -12,6 +12,7 @@ import { getBlockEditingMode, isBlockSubtreeDisabled, getListViewClientIdsTree, + getEnabledBlockParents, } from '../private-selectors'; jest.mock( '@wordpress/data/src/select', () => ( { @@ -554,4 +555,99 @@ describe( 'private selectors', () => { ] ); } ); } ); + + describe( 'getEnabledBlockParents', () => { + it( 'should return an empty array if block is at the root', () => { + const state = { + settings: {}, + blocks: { + parents: new Map( [ + [ '6cf70164-9097-4460-bcbf-200560546988', '' ], + ] ), + }, + blockEditingModes: new Map(), + }; + expect( + getEnabledBlockParents( + state, + '6cf70164-9097-4460-bcbf-200560546988' + ) + ).toEqual( [] ); + } ); + + it( 'should return non-disabled parents', () => { + const state = { + settings: {}, + blocks: { + parents: new Map( [ + [ 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', '' ], + [ + '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f', + 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', + ], + [ + 'e178812d-ce5e-48c7-a945-8ae4ffcbbb7c', + '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f', + ], + [ + '4c2b7140-fffd-44b4-b2a7-820c670a6514', + 'e178812d-ce5e-48c7-a945-8ae4ffcbbb7c', + ], + ] ), + }, + blockEditingModes: new Map( [ + [ '', 'disabled' ], + [ '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f', 'default' ], + ] ), + blockListSettings: {}, + }; + expect( + getEnabledBlockParents( + state, + '4c2b7140-fffd-44b4-b2a7-820c670a6514' + ) + ).toEqual( [ + '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f', + 'e178812d-ce5e-48c7-a945-8ae4ffcbbb7c', + ] ); + } ); + + it( 'should order from bottom to top if ascending is true', () => { + const state = { + settings: {}, + blocks: { + parents: new Map( [ + [ 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', '' ], + [ + '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f', + 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', + ], + [ + 'e178812d-ce5e-48c7-a945-8ae4ffcbbb7c', + '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f', + ], + [ + '4c2b7140-fffd-44b4-b2a7-820c670a6514', + 'e178812d-ce5e-48c7-a945-8ae4ffcbbb7c', + ], + ] ), + }, + blockEditingModes: new Map( [ + [ '', 'disabled' ], + [ '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f', 'default' ], + ] ), + blockListSettings: {}, + }; + expect( + getEnabledBlockParents( + state, + '4c2b7140-fffd-44b4-b2a7-820c670a6514', + true + ) + ).toEqual( [ + 'e178812d-ce5e-48c7-a945-8ae4ffcbbb7c', + '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f', + ] ); + } ); + } ); } );