Skip to content

Commit 121e3d2

Browse files
committed
useSlotFills: trigger state update only on array length change
1 parent 514f609 commit 121e3d2

1 file changed

Lines changed: 29 additions & 3 deletions

File tree

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,42 @@
11
/**
22
* WordPress dependencies
33
*/
4-
import { useContext } from '@wordpress/element';
5-
import { useObservableValue } from '@wordpress/compose';
4+
import { useContext, useMemo, useSyncExternalStore } from '@wordpress/element';
5+
import type { ObservableMap } from '@wordpress/compose';
66

77
/**
88
* Internal dependencies
99
*/
1010
import SlotFillContext from '../context';
1111
import type { SlotKey } from '../types';
1212

13+
function useObservableValueWithSelector< K, V, S >(
14+
map: ObservableMap< K, V >,
15+
name: K,
16+
selector: ( v: V | undefined ) => S
17+
) {
18+
const subscribe = useMemo(
19+
() => ( listener: () => void ) => map.subscribe( name, listener ),
20+
[ map, name ]
21+
);
22+
const getValue = () => selector( map.get( name ) );
23+
return useSyncExternalStore( subscribe, getValue, getValue );
24+
}
25+
26+
function getLength< T >( array: T[] | undefined ) {
27+
return array?.length;
28+
}
29+
1330
export default function useSlotFills( name: SlotKey ) {
1431
const registry = useContext( SlotFillContext );
15-
return useObservableValue( registry.fills, name );
32+
const length = useObservableValueWithSelector(
33+
registry.fills,
34+
name,
35+
getLength
36+
);
37+
// callers expect an opaque array with length `length`, so create that array
38+
const fills = useMemo( () => {
39+
return length !== undefined ? Array.from( { length } ) : undefined;
40+
}, [ length ] );
41+
return fills;
1642
}

0 commit comments

Comments
 (0)