Skip to content

Commit

Permalink
ToolsPanel: Memoize callbacks and context to prevent unnecessary rere…
Browse files Browse the repository at this point in the history
…nders (#38037)

* Prevent BlockSupportToolsPanel resetAll triggering rerenders
* Add memoization to ToolsPanel callbacks and context
* Add changelog
  • Loading branch information
aaronrobertshaw committed Jan 21, 2022
1 parent 210af7e commit fa82344
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 148 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
import { __experimentalToolsPanel as ToolsPanel } from '@wordpress/components';
import { useDispatch, useSelect } from '@wordpress/data';
import { useCallback } from '@wordpress/element';

/**
* Internal dependencies
Expand All @@ -11,74 +12,54 @@ import { store as blockEditorStore } from '../../store';
import { cleanEmptyObject } from '../../hooks/utils';

export default function BlockSupportToolsPanel( { children, group, label } ) {
const { attributes, clientIds, panelId } = useSelect( ( select ) => {
const {
getBlockAttributes,
getMultiSelectedBlockClientIds,
getSelectedBlockClientId,
hasMultiSelection,
} = select( blockEditorStore );

// When we currently have a multi-selection, the value returned from
// `getSelectedBlockClientId()` is `null`. When a `null` value is used
// for the `panelId`, a `ToolsPanel` will still allow panel items to
// register themselves despite their panelIds not matching.
const selectedBlockClientId = getSelectedBlockClientId();

if ( hasMultiSelection() ) {
const selectedBlockClientIds = getMultiSelectedBlockClientIds();
const selectedBlockAttributes = selectedBlockClientIds.reduce(
( blockAttributes, blockId ) => {
blockAttributes[ blockId ] = getBlockAttributes( blockId );
return blockAttributes;
},
{}
);
const { updateBlockAttributes } = useDispatch( blockEditorStore );
const {
getBlockAttributes,
getMultiSelectedBlockClientIds,
getSelectedBlockClientId,
hasMultiSelection,
} = useSelect( blockEditorStore );

return {
panelId: selectedBlockClientId,
clientIds: selectedBlockClientIds,
attributes: selectedBlockAttributes,
};
}
const panelId = getSelectedBlockClientId();
const resetAll = useCallback(
( resetFilters = [] ) => {
const newAttributes = {};

return {
panelId: selectedBlockClientId,
clientIds: [ selectedBlockClientId ],
attributes: {
[ selectedBlockClientId ]: getBlockAttributes(
selectedBlockClientId
),
},
};
}, [] );
const { updateBlockAttributes } = useDispatch( blockEditorStore );
const clientIds = hasMultiSelection()
? getMultiSelectedBlockClientIds()
: [ panelId ];

const resetAll = ( resetFilters = [] ) => {
const newAttributes = {};
clientIds.forEach( ( clientId ) => {
const { style } = getBlockAttributes( clientId );
let newBlockAttributes = { style };

clientIds.forEach( ( clientId ) => {
const { style } = attributes[ clientId ];
let newBlockAttributes = { style };
resetFilters.forEach( ( resetFilter ) => {
newBlockAttributes = {
...newBlockAttributes,
...resetFilter( newBlockAttributes ),
};
} );

resetFilters.forEach( ( resetFilter ) => {
// Enforce a cleaned style object.
newBlockAttributes = {
...newBlockAttributes,
...resetFilter( newBlockAttributes ),
style: cleanEmptyObject( newBlockAttributes.style ),
};
} );

// Enforce a cleaned style object.
newBlockAttributes = {
...newBlockAttributes,
style: cleanEmptyObject( newBlockAttributes.style ),
};

newAttributes[ clientId ] = newBlockAttributes;
} );
newAttributes[ clientId ] = newBlockAttributes;
} );

updateBlockAttributes( clientIds, newAttributes, true );
};
updateBlockAttributes( clientIds, newAttributes, true );
},
[
cleanEmptyObject,
getBlockAttributes,
getMultiSelectedBlockClientIds,
hasMultiSelection,
panelId,
updateBlockAttributes,
]
);

return (
<ToolsPanel
Expand Down
1 change: 1 addition & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- Add missing styles to the `BaseControl.VisualLabel` component. ([#37747](https://github.com/WordPress/gutenberg/pull/37747))
- Prevent keyDown events from propagating up in `CustomSelectControl` ([#30557](https://github.com/WordPress/gutenberg/pull/30557))
- Mark `children` prop as optional in `SelectControl` ([#37872](https://github.com/WordPress/gutenberg/pull/37872))
- Add memoization of callbacks and context to prevent unnecessary rerenders of the `ToolsPanel` ([#38037](https://github.com/WordPress/gutenberg/pull/38037))

## 19.2.0 (2022-01-04)

Expand Down
Loading

0 comments on commit fa82344

Please sign in to comment.