@wordpress/block-editor
Version:
72 lines (66 loc) • 2.23 kB
JavaScript
/**
* WordPress dependencies
*/
import {
createContext,
useCallback,
useContext,
useMemo,
} from '@wordpress/element';
/**
* Internal dependencies
*/
import { useBlockEditContext } from '../block-edit/context';
const RenderedRefsContext = createContext( {} );
/**
* Immutably adds an unique identifier to a set scoped for a given block type.
*
* @param {Object} renderedBlocks Rendered blocks grouped by block name
* @param {string} blockName Name of the block.
* @param {*} uniqueId Any value that acts as a unique identifier for a block instance.
*
* @return {Object} The list of rendered blocks grouped by block name.
*/
function addToBlockType( renderedBlocks, blockName, uniqueId ) {
const result = {
...renderedBlocks,
[ blockName ]: renderedBlocks[ blockName ]
? new Set( renderedBlocks[ blockName ] )
: new Set(),
};
result[ blockName ].add( uniqueId );
return result;
}
/**
* A React hook for keeping track of blocks previously rendered up in the block
* tree. Blocks susceptible to recursion can use this hook in their `Edit`
* function to prevent said recursion.
*
* @param {*} uniqueId Any value that acts as a unique identifier for a block instance.
*
* @return {[boolean, Function]} A tuple of:
* - a boolean describing whether the provided id
* has already been rendered;
* - a React context provider to be used to wrap
* other elements.
*/
export default function useNoRecursiveRenders( uniqueId ) {
const previouslyRenderedBlocks = useContext( RenderedRefsContext );
const { name: blockName } = useBlockEditContext();
const hasAlreadyRendered = Boolean(
previouslyRenderedBlocks[ blockName ]?.has( uniqueId )
);
const newRenderedBlocks = useMemo(
() => addToBlockType( previouslyRenderedBlocks, blockName, uniqueId ),
[ previouslyRenderedBlocks, blockName, uniqueId ]
);
const Provider = useCallback(
( { children } ) => (
<RenderedRefsContext.Provider value={ newRenderedBlocks }>
{ children }
</RenderedRefsContext.Provider>
),
[ newRenderedBlocks ]
);
return [ hasAlreadyRendered, Provider ];
}