From 8bd3d46a5331dd855bd1a3f386a690bfd628a2a1 Mon Sep 17 00:00:00 2001 From: Ella <4710635+ellatrix@users.noreply.github.com> Date: Tue, 21 May 2024 14:51:05 +0200 Subject: [PATCH] Perf: batch block list settings in single action (#61329) Co-authored-by: ellatrix Co-authored-by: jsnajdr --- .../data/data-core-block-editor.md | 4 +-- .../use-nested-settings-update.js | 25 +++++-------- packages/block-editor/src/store/actions.js | 15 +++++--- packages/block-editor/src/store/reducer.js | 35 +++++++++++++------ 4 files changed, 46 insertions(+), 33 deletions(-) diff --git a/docs/reference-guides/data/data-core-block-editor.md b/docs/reference-guides/data/data-core-block-editor.md index 486fcddfe04ac..862a8b2d8a06a 100644 --- a/docs/reference-guides/data/data-core-block-editor.md +++ b/docs/reference-guides/data/data-core-block-editor.md @@ -1841,11 +1841,11 @@ _Returns_ ### updateBlockListSettings -Action that changes the nested settings of a given block. +Action that changes the nested settings of the given block(s). _Parameters_ -- _clientId_ `string`: Client ID of the block whose nested setting are being received. +- _clientId_ `string | SettingsByClientId`: Client ID of the block whose nested setting are being received, or object of settings by client ID. - _settings_ `Object`: Object with the new settings for the nested block. _Returns_ diff --git a/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js b/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js index 25a3dc9dadfa9..8417dec1dd48f 100644 --- a/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js +++ b/packages/block-editor/src/components/inner-blocks/use-nested-settings-update.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { useLayoutEffect, useMemo, useState } from '@wordpress/element'; -import { useDispatch, useRegistry } from '@wordpress/data'; +import { useRegistry } from '@wordpress/data'; import deprecated from '@wordpress/deprecated'; import isShallowEqual from '@wordpress/is-shallow-equal'; @@ -69,7 +69,6 @@ export default function useNestedSettingsUpdate( // Instead of adding a useSelect mapping here, please add to the useSelect // mapping in InnerBlocks! Every subscription impacts performance. - const { updateBlockListSettings } = useDispatch( blockEditorStore ); const registry = useRegistry(); // Implementors often pass a new array on every render, @@ -155,21 +154,16 @@ export default function useNestedSettingsUpdate( // we batch all the updatedBlockListSettings in a single "data" batch // which results in a single re-render. if ( ! pendingSettingsUpdates.get( registry ) ) { - pendingSettingsUpdates.set( registry, [] ); + pendingSettingsUpdates.set( registry, {} ); } - pendingSettingsUpdates - .get( registry ) - .push( [ clientId, newSettings ] ); + pendingSettingsUpdates.get( registry )[ clientId ] = newSettings; window.queueMicrotask( () => { - if ( pendingSettingsUpdates.get( registry )?.length ) { - registry.batch( () => { - pendingSettingsUpdates - .get( registry ) - .forEach( ( args ) => { - updateBlockListSettings( ...args ); - } ); - pendingSettingsUpdates.set( registry, [] ); - } ); + const settings = pendingSettingsUpdates.get( registry ); + if ( Object.keys( settings ).length ) { + const { updateBlockListSettings } = + registry.dispatch( blockEditorStore ); + updateBlockListSettings( settings ); + pendingSettingsUpdates.set( registry, {} ); } } ); }, [ @@ -183,7 +177,6 @@ export default function useNestedSettingsUpdate( __experimentalDirectInsert, captureToolbars, orientation, - updateBlockListSettings, layout, registry, ] ); diff --git a/packages/block-editor/src/store/actions.js b/packages/block-editor/src/store/actions.js index d6eaac9c7e8c9..c9a1430a078fa 100644 --- a/packages/block-editor/src/store/actions.js +++ b/packages/block-editor/src/store/actions.js @@ -1506,11 +1506,18 @@ export const insertDefaultBlock = }; /** - * Action that changes the nested settings of a given block. + * @typedef {Object< string, Object >} SettingsByClientId + */ + +/** + * Action that changes the nested settings of the given block(s). * - * @param {string} clientId Client ID of the block whose nested setting are - * being received. - * @param {Object} settings Object with the new settings for the nested block. + * @param {string | SettingsByClientId} clientId Client ID of the block whose + * nested setting are being + * received, or object of settings + * by client ID. + * @param {Object} settings Object with the new settings + * for the nested block. * * @return {Object} Action object */ diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js index 3ea0fb4627304..7c83887876919 100644 --- a/packages/block-editor/src/store/reducer.js +++ b/packages/block-editor/src/store/reducer.js @@ -1750,24 +1750,37 @@ export const blockListSettings = ( state = {}, action ) => { ); } case 'UPDATE_BLOCK_LIST_SETTINGS': { - const { clientId } = action; - if ( ! action.settings ) { - if ( state.hasOwnProperty( clientId ) ) { - const { [ clientId ]: removedBlock, ...restBlocks } = state; - return restBlocks; + const updates = + typeof action.clientId === 'string' + ? { [ action.clientId ]: action.settings } + : action.clientId; + + // Remove settings that are the same as the current state. + for ( const clientId in updates ) { + if ( ! updates[ clientId ] ) { + if ( ! state[ clientId ] ) { + delete updates[ clientId ]; + } + } else if ( + fastDeepEqual( state[ clientId ], updates[ clientId ] ) + ) { + delete updates[ clientId ]; } + } + if ( Object.keys( updates ).length === 0 ) { return state; } - if ( fastDeepEqual( state[ clientId ], action.settings ) ) { - return state; + const merged = { ...state, ...updates }; + + for ( const clientId in updates ) { + if ( ! updates[ clientId ] ) { + delete merged[ clientId ]; + } } - return { - ...state, - [ clientId ]: action.settings, - }; + return merged; } } return state;