diff --git a/packages/block-editor/src/hooks/use-bindings-attributes.js b/packages/block-editor/src/hooks/use-bindings-attributes.js
index 5cd8cb46b3b7e..b2bc7bdc9f81f 100644
--- a/packages/block-editor/src/hooks/use-bindings-attributes.js
+++ b/packages/block-editor/src/hooks/use-bindings-attributes.js
@@ -4,7 +4,7 @@
import { getBlockType, store as blocksStore } from '@wordpress/blocks';
import { createHigherOrderComponent } from '@wordpress/compose';
import { useSelect } from '@wordpress/data';
-import { useLayoutEffect, useCallback, useState } from '@wordpress/element';
+import { useCallback, useReducer } from '@wordpress/element';
import { addFilter } from '@wordpress/hooks';
import { RichTextData } from '@wordpress/rich-text';
@@ -89,11 +89,16 @@ const BindingConnector = ( {
* If the attribute is a RichTextData instance,
* (core/paragraph, core/heading, core/button, etc.)
* compare its HTML representation with the new value.
- *
- * To do: it looks like a workaround.
- * Consider improving the attribute and metadata fields types.
*/
if ( prevAttrValue instanceof RichTextData ) {
+ // If the new value is also a RichTextData instance and the value is the same, bail early.
+ if (
+ newAttrValue instanceof RichTextData &&
+ prevAttrValue.toHTMLString() === newAttrValue.toHTMLString()
+ ) {
+ return;
+ }
+
// Bail early if the Rich Text value is the same.
if ( prevAttrValue.toHTMLString() === newAttrValue ) {
return;
@@ -106,6 +111,7 @@ const BindingConnector = ( {
newAttrValue = RichTextData.fromHTMLString( newAttrValue );
}
+ // Bail early if the attribute value is the same.
if ( prevAttrValue === newAttrValue ) {
return;
}
@@ -115,35 +121,26 @@ const BindingConnector = ( {
[ attrName, onPropValueChange ]
);
- useLayoutEffect( () => {
- if ( typeof propValue !== 'undefined' ) {
- updateBoundAttibute( propValue, attrValue );
- } else if ( placeholder ) {
- /*
- * Placeholder fallback.
- * If the attribute is `src` or `href`,
- * a placeholder can't be used because it is not a valid url.
- * Adding this workaround until
- * attributes and metadata fields types are improved and include `url`.
- */
- const htmlAttribute =
- getBlockType( blockName ).attributes[ attrName ].attribute;
-
- if ( htmlAttribute === 'src' || htmlAttribute === 'href' ) {
- updateBoundAttibute( null );
- return;
- }
+ if ( typeof propValue !== 'undefined' ) {
+ updateBoundAttibute( propValue, attrValue );
+ } else if ( placeholder ) {
+ /*
+ * Placeholder fallback.
+ * If the attribute is `src` or `href`,
+ * a placeholder can't be used because it is not a valid url.
+ * Adding this workaround until
+ * attributes and metadata fields types are improved and include `url`.
+ */
+ const htmlAttribute =
+ getBlockType( blockName ).attributes[ attrName ].attribute;
- updateBoundAttibute( placeholder );
+ if ( htmlAttribute === 'src' || htmlAttribute === 'href' ) {
+ updateBoundAttibute( null, attrValue );
+ return null;
}
- }, [
- updateBoundAttibute,
- propValue,
- attrValue,
- placeholder,
- blockName,
- attrName,
- ] );
+
+ updateBoundAttibute( placeholder, attrValue );
+ }
return null;
};
@@ -194,18 +191,17 @@ function BlockBindingBridge( { blockProps, bindings, onPropValueChange } ) {
const withBlockBindingSupport = createHigherOrderComponent(
( BlockEdit ) => ( props ) => {
+ function attributeReducer( state, newAttibutes ) {
+ return { ...state, ...newAttibutes };
+ }
+
/*
* Collect and update the bound attributes
* in a separate state.
*/
- const [ boundAttributes, setBoundAttributes ] = useState( {} );
- const updateBoundAttributes = useCallback(
- ( newAttributes ) =>
- setBoundAttributes( ( prev ) => ( {
- ...prev,
- ...newAttributes,
- } ) ),
- []
+ const [ boundAttributes, updateBoundAttributes ] = useReducer(
+ attributeReducer,
+ props.attributes
);
/*
@@ -222,16 +218,13 @@ const withBlockBindingSupport = createHigherOrderComponent(
<>
{ Object.keys( bindings ).length > 0 && (
) }
-
+
>
);
},