UNPKG

@wordpress/data

Version:
111 lines (104 loc) 4.23 kB
/** * Internal dependencies */ import type { select as globalSelect } from './select'; type RegistrySelector< Selector extends ( ...args: any[] ) => any > = { ( ...args: Parameters< Selector > ): ReturnType< Selector >; isRegistrySelector?: boolean; registry?: any; }; /** * Creates a selector function that takes additional curried argument with the * registry `select` function. While a regular selector has signature * ```js * ( state, ...selectorArgs ) => ( result ) * ``` * that allows to select data from the store's `state`, a registry selector * has signature: * ```js * ( select ) => ( state, ...selectorArgs ) => ( result ) * ``` * that supports also selecting from other registered stores. * * @example * ```js * import { store as coreStore } from '@wordpress/core-data'; * import { store as editorStore } from '@wordpress/editor'; * * const getCurrentPostId = createRegistrySelector( ( select ) => ( state ) => { * return select( editorStore ).getCurrentPostId(); * } ); * * const getPostEdits = createRegistrySelector( ( select ) => ( state ) => { * // calling another registry selector just like any other function * const postType = getCurrentPostType( state ); * const postId = getCurrentPostId( state ); * return select( coreStore ).getEntityRecordEdits( 'postType', postType, postId ); * } ); * ``` * * Note how the `getCurrentPostId` selector can be called just like any other function, * (it works even inside a regular non-registry selector) and we don't need to pass the * registry as argument. The registry binding happens automatically when registering the selector * with a store. * * @param registrySelector Function receiving a registry `select` * function and returning a state selector. * * @return Registry selector that can be registered with a store. */ export function createRegistrySelector< Selector extends ( ...args: any[] ) => any, >( registrySelector: ( select: typeof globalSelect ) => Selector ): RegistrySelector< Selector > { const selectorsByRegistry = new WeakMap(); // Create a selector function that is bound to the registry referenced by `selector.registry` // and that has the same API as a regular selector. Binding it in such a way makes it // possible to call the selector directly from another selector. const wrappedSelector: RegistrySelector< Selector > = ( ...args ) => { let selector = selectorsByRegistry.get( wrappedSelector.registry ); // We want to make sure the cache persists even when new registry // instances are created. For example patterns create their own editors // with their own core/block-editor stores, so we should keep track of // the cache for each registry instance. if ( ! selector ) { selector = registrySelector( wrappedSelector.registry.select ); selectorsByRegistry.set( wrappedSelector.registry, selector ); } return selector( ...args ); }; /** * Flag indicating that the selector is a registry selector that needs the correct registry * reference to be assigned to `selector.registry` to make it work correctly. * be mapped as a registry selector. */ wrappedSelector.isRegistrySelector = true; return wrappedSelector; } /** * Creates a control function that takes additional curried argument with the `registry` object. * While a regular control has signature * ```js * ( action ) => ( iteratorOrPromise ) * ``` * where the control works with the `action` that it's bound to, a registry control has signature: * ```js * ( registry ) => ( action ) => ( iteratorOrPromise ) * ``` * A registry control is typically used to select data or dispatch an action to a registered * store. * * When registering a control created with `createRegistryControl` with a store, the store * knows which calling convention to use when executing the control. * * @param registryControl Function receiving a registry object and returning a control. * * @return Registry control that can be registered with a store. */ export function createRegistryControl< T extends ( ...args: any ) => any >( registryControl: T & { isRegistryControl?: boolean } ) { registryControl.isRegistryControl = true; return registryControl; }