Ensure Product Collection Block's `queryId` Uniqueness (#44522)

Since we don't need it to be _perfectly_ stable,
we can just set the `queryId` to the instance ID
on every component mounting. This is fine and
won't mark the attribute as dirty unless a
collection block is added, deleted, or moved
in just the right way. The exception to this
is collection blocks in sync patterns.
In this case the ID cannot change
because it can cause update loops in some
cases that freeze the browser.
This commit is contained in:
Christopher Allford 2024-03-22 01:40:15 -07:00 committed by GitHub
parent 5002b62d00
commit b8bd480faf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 51 additions and 23 deletions

View File

@ -1,9 +1,14 @@
/**
* External dependencies
*/
import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
import {
useBlockProps,
useInnerBlocksProps,
store as blockEditorStore,
} from '@wordpress/block-editor';
import { useInstanceId } from '@wordpress/compose';
import { useEffect } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
/**
* Internal dependencies
@ -22,8 +27,7 @@ import ToolbarControls from './toolbar-controls';
const ProductCollectionContent = (
props: ProductCollectionEditComponentProps
) => {
const { attributes, setAttributes } = props;
const { queryId } = attributes;
const { clientId, attributes, setAttributes } = props;
const blockProps = useBlockProps();
const innerBlocksProps = useInnerBlocksProps( blockProps, {
@ -31,32 +35,52 @@ const ProductCollectionContent = (
} );
const instanceId = useInstanceId( ProductCollectionContent );
// We need this for multi-query block pagination.
// Query parameters for each block are scoped to their ID.
useEffect( () => {
if ( ! Number.isFinite( queryId ) ) {
setAttributes( { queryId: Number( instanceId ) } );
}
}, [ queryId, instanceId, setAttributes ] );
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore These selectors aren't getting their types loaded for some reason.
const { getBlockParentsByBlockName } = useSelect( blockEditorStore );
/**
* Because of issue https://github.com/WordPress/gutenberg/issues/7342,
* We are using this workaround to set default attributes.
*/
useEffect( () => {
setAttributes( {
...DEFAULT_ATTRIBUTES,
query: {
...( DEFAULT_ATTRIBUTES.query as ProductCollectionQuery ),
inherit: getDefaultValueOfInheritQueryFromTemplate(),
},
...( attributes as Partial< ProductCollectionAttributes > ),
} );
// We don't wanna add attributes as a dependency here.
// Because we want this to run only once.
useEffect(
() => {
// In order to properly support pagination this block has a queryId attribute that
// is initialized to a unique value when the block is first added to the editor.
// We use the `instanceId` for this purpose. It is stable across saves as long
// as the order of instances of these blocks in the editor does not change.
// The block will be re-indexed in that case, however, this won't cause
// any problems since the queryid only has to be stable across client
// renders.
let queryId = instanceId as number;
// We need to take special care when handling instances in a sync pattern
// to avoid an infinite loop. When two instances of a pattern are placed
// on the same page, updating one will cause the other to be re-inserted.
// If we change the ID on init it will trigger a loop as each competes
// to set a new queryId and update the sync pattern.
const blockParents = getBlockParentsByBlockName(
clientId,
'core/block'
);
if ( blockParents.length > 0 ) {
queryId = attributes.queryId;
}
setAttributes( {
...DEFAULT_ATTRIBUTES,
query: {
...( DEFAULT_ATTRIBUTES.query as ProductCollectionQuery ),
inherit: getDefaultValueOfInheritQueryFromTemplate(),
},
...( attributes as Partial< ProductCollectionAttributes > ),
queryId,
} );
},
// This hook is only needed on initialization and sets default attributes.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ setAttributes ] );
[]
);
/**
* If inherit is not a boolean, then we haven't set default attributes yet.

View File

@ -0,0 +1,4 @@
Significance: minor
Type: fix
Ensure queryId and id uniqueness when duplicating the Product Collection block.