Skip to content
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

Block editor: make all BlockEdit hooks pure #56813

Merged
merged 4 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions packages/block-editor/src/hooks/align.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { createHigherOrderComponent } from '@wordpress/compose';
import { createHigherOrderComponent, pure } from '@wordpress/compose';
import { addFilter } from '@wordpress/hooks';
import {
getBlockSupport,
Expand Down Expand Up @@ -108,9 +108,9 @@ export function addAttribute( settings ) {
return settings;
}

function BlockEditAlignmentToolbarControls( {
function BlockEditAlignmentToolbarControlsPure( {
blockName,
attributes,
align,
setAttributes,
} ) {
// Compute the block valid alignments by taking into account,
Expand Down Expand Up @@ -144,14 +144,21 @@ function BlockEditAlignmentToolbarControls( {
return (
<BlockControls group="block" __experimentalShareWithChildBlocks>
<BlockAlignmentControl
value={ attributes.align }
value={ align }
onChange={ updateAlignment }
controls={ validAlignments }
/>
</BlockControls>
);
}

// We don't want block controls to re-render when typing inside a block. `pure`
// will prevent re-renders unless props change, so only pass the needed props
// and not the whole attributes object.
const BlockEditAlignmentToolbarControls = pure(
BlockEditAlignmentToolbarControlsPure
);

/**
* Override the default edit UI to include new toolbar controls for block
* alignment, if block defines support.
Expand All @@ -173,7 +180,8 @@ export const withAlignmentControls = createHigherOrderComponent(
{ hasAlignmentSupport && (
<BlockEditAlignmentToolbarControls
blockName={ props.name }
attributes={ props.attributes }
// This component is pure, so only pass needed props!
align={ props.attributes.align }
setAttributes={ props.setAttributes }
/>
) }
Expand Down
15 changes: 11 additions & 4 deletions packages/block-editor/src/hooks/anchor.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { addFilter } from '@wordpress/hooks';
import { PanelBody, TextControl, ExternalLink } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { hasBlockSupport } from '@wordpress/blocks';
import { createHigherOrderComponent } from '@wordpress/compose';
import { createHigherOrderComponent, pure } from '@wordpress/compose';
import { Platform } from '@wordpress/element';

/**
Expand Down Expand Up @@ -52,7 +52,7 @@ export function addAttribute( settings ) {
return settings;
}

function BlockEditAnchorControl( { blockName, attributes, setAttributes } ) {
function BlockEditAnchorControlPure( { blockName, anchor, setAttributes } ) {
const blockEditingMode = useBlockEditingMode();

const isWeb = Platform.OS === 'web';
Expand All @@ -79,7 +79,7 @@ function BlockEditAnchorControl( { blockName, attributes, setAttributes } ) {
) }
</>
}
value={ attributes.anchor || '' }
value={ anchor || '' }
placeholder={ ! isWeb ? __( 'Add an anchor' ) : null }
onChange={ ( nextValue ) => {
nextValue = nextValue.replace( ANCHOR_REGEX, '-' );
Expand Down Expand Up @@ -116,6 +116,11 @@ function BlockEditAnchorControl( { blockName, attributes, setAttributes } ) {
);
}

// We don't want block controls to re-render when typing inside a block. `pure`
// will prevent re-renders unless props change, so only pass the needed props
// and not the whole attributes object.
const BlockEditAnchorControl = pure( BlockEditAnchorControlPure );

/**
* Override the default edit UI to include a new block inspector control for
* assigning the anchor ID, if block supports anchor.
Expand All @@ -133,7 +138,9 @@ export const withAnchorControls = createHigherOrderComponent( ( BlockEdit ) => {
hasBlockSupport( props.name, 'anchor' ) && (
<BlockEditAnchorControl
blockName={ props.name }
attributes={ props.attributes }
// This component is pure, so only pass needed
// props!
anchor={ props.attributes.anchor }
setAttributes={ props.setAttributes }
/>
) }
Expand Down
3 changes: 3 additions & 0 deletions packages/block-editor/src/hooks/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -318,4 +318,7 @@ function BackgroundImagePanelPure( props ) {
);
}

// We don't want block controls to re-render when typing inside a block. `pure`
// will prevent re-renders unless props change, so only pass the needed props
// and not the whole attributes object.
export const BackgroundImagePanel = pure( BackgroundImagePanelPure );
9 changes: 7 additions & 2 deletions packages/block-editor/src/hooks/block-hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
PanelBody,
ToggleControl,
} from '@wordpress/components';
import { createHigherOrderComponent } from '@wordpress/compose';
import { createHigherOrderComponent, pure } from '@wordpress/compose';
import { createBlock, store as blocksStore } from '@wordpress/blocks';
import { useDispatch, useSelect } from '@wordpress/data';

Expand All @@ -21,7 +21,7 @@ import { store as blockEditorStore } from '../store';

const EMPTY_OBJECT = {};

function BlockHooksControl( props ) {
function BlockHooksControlPure( props ) {
const blockTypes = useSelect(
( select ) => select( blocksStore ).getBlockTypes(),
[]
Expand Down Expand Up @@ -235,6 +235,11 @@ function BlockHooksControl( props ) {
);
}

// We don't want block controls to re-render when typing inside a block. `pure`
// will prevent re-renders unless props change, so only pass the needed props
// and not the whole attributes object.
const BlockHooksControl = pure( BlockHooksControlPure );

export const withBlockHooksControls = createHigherOrderComponent(
( BlockEdit ) => {
return ( props ) => {
Expand Down
56 changes: 36 additions & 20 deletions packages/block-editor/src/hooks/block-renaming.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/
import { addFilter } from '@wordpress/hooks';
import { hasBlockSupport } from '@wordpress/blocks';
import { createHigherOrderComponent } from '@wordpress/compose';
import { createHigherOrderComponent, pure } from '@wordpress/compose';
import { __ } from '@wordpress/i18n';
import { TextControl } from '@wordpress/components';

Expand Down Expand Up @@ -47,30 +47,46 @@ export function addLabelCallback( settings ) {
return settings;
}

function BlockRenameControlPure( { name, metadata, setAttributes } ) {
const { canRename } = useBlockRename( name );

if ( ! canRename ) {
return null;
}

return (
<InspectorControls group="advanced">
<TextControl
__nextHasNoMarginBottom
label={ __( 'Block name' ) }
value={ metadata?.name || '' }
onChange={ ( newName ) => {
setAttributes( {
metadata: { ...metadata, name: newName },
} );
} }
/>
</InspectorControls>
);
}

// We don't want block controls to re-render when typing inside a block. `pure`
// will prevent re-renders unless props change, so only pass the needed props
// and not the whole attributes object.
const BlockRenameControl = pure( BlockRenameControlPure );

export const withBlockRenameControl = createHigherOrderComponent(
( BlockEdit ) => ( props ) => {
const { name, attributes, setAttributes, isSelected } = props;

const { canRename } = useBlockRename( name );

return (
<>
{ isSelected && canRename && (
<InspectorControls group="advanced">
<TextControl
__nextHasNoMarginBottom
label={ __( 'Block name' ) }
value={ attributes?.metadata?.name || '' }
onChange={ ( newName ) => {
setAttributes( {
metadata: {
...attributes?.metadata,
name: newName,
},
} );
} }
/>
</InspectorControls>
{ isSelected && (
<BlockRenameControl
name={ name }
// This component is pure, so only pass needed props!
metadata={ attributes.metadata }
setAttributes={ setAttributes }
/>
) }
<BlockEdit key="edit" { ...props } />
</>
Expand Down
3 changes: 3 additions & 0 deletions packages/block-editor/src/hooks/border.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,9 @@ function BorderPanelPure( { clientId, name, setAttributes } ) {
);
}

// We don't want block controls to re-render when typing inside a block. `pure`
// will prevent re-renders unless props change, so only pass the needed props
// and not the whole attributes object.
export const BorderPanel = pure( BorderPanelPure );

/**
Expand Down
3 changes: 3 additions & 0 deletions packages/block-editor/src/hooks/color.js
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,9 @@ function ColorEditPure( { clientId, name, setAttributes } ) {
);
}

// We don't want block controls to re-render when typing inside a block. `pure`
// will prevent re-renders unless props change, so only pass the needed props
// and not the whole attributes object.
export const ColorEdit = pure( ColorEditPure );

/**
Expand Down
Loading
Loading