From 572587ef99febf50e30c0cec996019e19c7dcc4d Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Tue, 10 Jan 2023 17:39:04 +0400 Subject: [PATCH 1/5] Block Editor: Add a new hook for getting a stable block context object --- .../src/components/inner-blocks/index.js | 27 ++---------- .../inner-blocks/use-block-context.js | 43 +++++++++++++++++++ 2 files changed, 47 insertions(+), 23 deletions(-) create mode 100644 packages/block-editor/src/components/inner-blocks/use-block-context.js diff --git a/packages/block-editor/src/components/inner-blocks/index.js b/packages/block-editor/src/components/inner-blocks/index.js index 0512569fb3f42d..6be5ae690f7243 100644 --- a/packages/block-editor/src/components/inner-blocks/index.js +++ b/packages/block-editor/src/components/inner-blocks/index.js @@ -11,7 +11,6 @@ import { forwardRef, useMemo } from '@wordpress/element'; import { useSelect } from '@wordpress/data'; import { getBlockSupport, - getBlockType, store as blocksStore, __unstableGetInnerBlocksProps as getInnerBlocksProps, } from '@wordpress/blocks'; @@ -23,7 +22,7 @@ import ButtonBlockAppender from './button-block-appender'; import DefaultBlockAppender from './default-block-appender'; import useNestedSettingsUpdate from './use-nested-settings-update'; import useInnerBlockTemplateSync from './use-inner-block-template-sync'; -import getBlockContext from './get-block-context'; +import useBlockContext from './use-block-context'; import { BlockListItems } from '../block-list'; import { BlockContextProvider } from '../block-context'; import { useBlockEditContext } from '../block-edit/context'; @@ -75,28 +74,10 @@ function UncontrolledInnerBlocks( props ) { templateInsertUpdatesSelection ); - const { context, name } = useSelect( + const context = useBlockContext( clientId ); + const name = useSelect( ( select ) => { - const block = select( blockEditorStore ).getBlock( clientId ); - - // This check is here to avoid the Redux zombie bug where a child subscription - // is called before a parent, causing potential JS errors when the child has been removed. - if ( ! block ) { - return {}; - } - - const blockType = getBlockType( block.name ); - - if ( - Object.keys( blockType?.providesContext ?? {} ).length === 0 - ) { - return { name: block.name }; - } - - return { - context: getBlockContext( block.attributes, blockType ), - name: block.name, - }; + return select( blockEditorStore ).getBlock( clientId )?.name; }, [ clientId ] ); diff --git a/packages/block-editor/src/components/inner-blocks/use-block-context.js b/packages/block-editor/src/components/inner-blocks/use-block-context.js new file mode 100644 index 00000000000000..4319d11a49813e --- /dev/null +++ b/packages/block-editor/src/components/inner-blocks/use-block-context.js @@ -0,0 +1,43 @@ +/** + * External dependencies + */ +import { mapValues } from 'lodash'; + +/** + * WordPress dependencies + */ +import { getBlockType } from '@wordpress/blocks'; +import { useSelect } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import { store as blockEditorStore } from '../../store'; + +/** + * Returns a context object for a given block. + * + * @param {string} clientId The block client ID. + * + * @return {Record} Context value. + */ +export default function useBlockContext( clientId ) { + return useSelect( + ( select ) => { + const block = select( blockEditorStore ).getBlock( clientId ); + const blockType = getBlockType( block.name ); + + if ( + Object.keys( blockType?.providesContext ?? {} ).length === 0 + ) { + return undefined; + } + + return mapValues( + blockType.providesContext, + ( attributeName ) => block.attributes[ attributeName ] + ); + }, + [ clientId ] + ); +} From 7ceabc983e638770da8d515a2c047f682dbb5993 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 12 Jan 2023 12:41:34 +0400 Subject: [PATCH 2/5] Update native files --- .../components/inner-blocks/index.native.js | 74 +++++++------------ 1 file changed, 27 insertions(+), 47 deletions(-) diff --git a/packages/block-editor/src/components/inner-blocks/index.native.js b/packages/block-editor/src/components/inner-blocks/index.native.js index 2b5ffe01aaf08c..3ba3b8e8321a2b 100644 --- a/packages/block-editor/src/components/inner-blocks/index.native.js +++ b/packages/block-editor/src/components/inner-blocks/index.native.js @@ -1,11 +1,7 @@ /** * WordPress dependencies */ -import { useSelect } from '@wordpress/data'; -import { - getBlockType, - __unstableGetInnerBlocksProps as getInnerBlocksProps, -} from '@wordpress/blocks'; +import { __unstableGetInnerBlocksProps as getInnerBlocksProps } from '@wordpress/blocks'; import { useRef } from '@wordpress/element'; /** @@ -15,7 +11,7 @@ import ButtonBlockAppender from './button-block-appender'; import DefaultBlockAppender from './default-block-appender'; import useNestedSettingsUpdate from './use-nested-settings-update'; import useInnerBlockTemplateSync from './use-inner-block-template-sync'; -import getBlockContext from './get-block-context'; +import useBlockContext from './use-block-context'; /** * Internal dependencies @@ -26,7 +22,6 @@ import { useBlockEditContext } from '../block-edit/context'; import useBlockSync from '../provider/use-block-sync'; import { BlockContextProvider } from '../block-context'; import { defaultLayout, LayoutProvider } from '../block-list/layout'; -import { store as blockEditorStore } from '../../store'; /** * This hook is used to lightly mark an element as an inner blocks wrapper @@ -100,10 +95,7 @@ function UncontrolledInnerBlocks( props ) { useCompactList, } = props; - const block = useSelect( - ( select ) => select( blockEditorStore ).getBlock( clientId ), - [ clientId ] - ) || { innerBlocks: [] }; + const context = useBlockContext( clientId ); useNestedSettingsUpdate( clientId, allowedBlocks, templateLock ); @@ -116,43 +108,31 @@ function UncontrolledInnerBlocks( props ) { const BlockListComponent = useCompactList ? BlockListCompact : BlockList; - let blockList = ( - + return ( + + + + + ); - - // Wrap context provider if (and only if) block has context to provide. - const blockType = getBlockType( block.name ); - if ( blockType && blockType.providesContext ) { - const context = getBlockContext( block.attributes, blockType ); - - blockList = ( - - - { blockList } - - - ); - } - - return blockList; } /** From 2a4af31b8ed36aae081535f11f996213709a9c0b Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 12 Jan 2023 12:42:45 +0400 Subject: [PATCH 3/5] Remove unused getBlockContext --- .../inner-blocks/get-block-context.js | 39 ------------------- 1 file changed, 39 deletions(-) delete mode 100644 packages/block-editor/src/components/inner-blocks/get-block-context.js diff --git a/packages/block-editor/src/components/inner-blocks/get-block-context.js b/packages/block-editor/src/components/inner-blocks/get-block-context.js deleted file mode 100644 index 295ef380d3808d..00000000000000 --- a/packages/block-editor/src/components/inner-blocks/get-block-context.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * External dependencies - */ -import { mapValues } from 'lodash'; - -/** - * Block context cache, implemented as a WeakMap mapping block types to a - * WeakMap mapping attributes object to context value. - * - * @type {WeakMap>} - */ -const BLOCK_CONTEXT_CACHE = new WeakMap(); - -/** - * Returns a cached context object value for a given set of attributes for the - * block type. - * - * @param {Record} attributes Block attributes object. - * @param {WPBlockType} blockType Block type settings. - * - * @return {Record} Context value. - */ -export default function getBlockContext( attributes, blockType ) { - if ( ! BLOCK_CONTEXT_CACHE.has( blockType ) ) { - BLOCK_CONTEXT_CACHE.set( blockType, new WeakMap() ); - } - - const blockTypeCache = BLOCK_CONTEXT_CACHE.get( blockType ); - if ( ! blockTypeCache.has( attributes ) ) { - const context = mapValues( - blockType.providesContext, - ( attributeName ) => attributes[ attributeName ] - ); - - blockTypeCache.set( attributes, context ); - } - - return blockTypeCache.get( attributes ); -} From 1904d75e6e94f21bd03cb955851426fc5d17a166 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 12 Jan 2023 12:58:14 +0400 Subject: [PATCH 4/5] The block can be undefined --- .../src/components/inner-blocks/use-block-context.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/inner-blocks/use-block-context.js b/packages/block-editor/src/components/inner-blocks/use-block-context.js index 4319d11a49813e..acecb49af82259 100644 --- a/packages/block-editor/src/components/inner-blocks/use-block-context.js +++ b/packages/block-editor/src/components/inner-blocks/use-block-context.js @@ -25,7 +25,7 @@ export default function useBlockContext( clientId ) { return useSelect( ( select ) => { const block = select( blockEditorStore ).getBlock( clientId ); - const blockType = getBlockType( block.name ); + const blockType = getBlockType( block?.name ); if ( Object.keys( blockType?.providesContext ?? {} ).length === 0 From 71e5776e0dbb5ae4855959b505a7496ddbc93232 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 12 Jan 2023 15:06:23 +0400 Subject: [PATCH 5/5] Address feedback --- .../inner-blocks/use-block-context.js | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/packages/block-editor/src/components/inner-blocks/use-block-context.js b/packages/block-editor/src/components/inner-blocks/use-block-context.js index acecb49af82259..885f8feda5c6f7 100644 --- a/packages/block-editor/src/components/inner-blocks/use-block-context.js +++ b/packages/block-editor/src/components/inner-blocks/use-block-context.js @@ -1,12 +1,7 @@ -/** - * External dependencies - */ -import { mapValues } from 'lodash'; - /** * WordPress dependencies */ -import { getBlockType } from '@wordpress/blocks'; +import { store as blocksStore } from '@wordpress/blocks'; import { useSelect } from '@wordpress/data'; /** @@ -25,17 +20,26 @@ export default function useBlockContext( clientId ) { return useSelect( ( select ) => { const block = select( blockEditorStore ).getBlock( clientId ); - const blockType = getBlockType( block?.name ); + if ( ! block ) { + return undefined; + } + + const blockType = select( blocksStore ).getBlockType( block.name ); + if ( ! blockType ) { + return undefined; + } - if ( - Object.keys( blockType?.providesContext ?? {} ).length === 0 - ) { + if ( Object.keys( blockType.providesContext ).length === 0 ) { return undefined; } - return mapValues( - blockType.providesContext, - ( attributeName ) => block.attributes[ attributeName ] + return Object.fromEntries( + Object.entries( blockType.providesContext ).map( + ( [ contextName, attributeName ] ) => [ + contextName, + block.attributes[ attributeName ], + ] + ) ); }, [ clientId ]