Skip to content

Commit

Permalink
useSlotFills: trigger state update only on array length change
Browse files Browse the repository at this point in the history
  • Loading branch information
jsnajdr committed Dec 20, 2024
1 parent 4be209d commit e569063
Showing 1 changed file with 29 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -1,16 +1,42 @@
/**
* WordPress dependencies
*/
import { useContext } from '@wordpress/element';
import { useObservableValue } from '@wordpress/compose';
import { useContext, useMemo, useSyncExternalStore } from '@wordpress/element';
import type { ObservableMap } from '@wordpress/compose';

/**
* Internal dependencies
*/
import SlotFillContext from '../context';
import type { SlotKey } from '../types';

function useObservableValueWithSelector< K, V, S >(
map: ObservableMap< K, V >,
name: K,
selector: ( v: V | undefined ) => S
) {
const subscribe = useMemo(
() => ( listener: () => void ) => map.subscribe( name, listener ),
[ map, name ]
);
const getValue = () => selector( map.get( name ) );
return useSyncExternalStore( subscribe, getValue, getValue );
}

function getLength< T >( array: T[] | undefined ) {
return array?.length;
}

export default function useSlotFills( name: SlotKey ) {
const registry = useContext( SlotFillContext );
return useObservableValue( registry.fills, name );
const length = useObservableValueWithSelector(
registry.fills,
name,
getLength
);
// callers expect an opaque array with length `length`, so create that array
const fills = useMemo( () => {
return length !== undefined ? Array.from( { length } ) : undefined;
}, [ length ] );
return fills;
}

0 comments on commit e569063

Please sign in to comment.