diff --git a/packages/core-data/src/selectors.js b/packages/core-data/src/selectors.js index b9ed8b575e086..36130c3439df6 100644 --- a/packages/core-data/src/selectors.js +++ b/packages/core-data/src/selectors.js @@ -7,7 +7,7 @@ import { map, find, get, filter, compact, defaultTo } from 'lodash'; /** * WordPress dependencies */ -import { select } from '@wordpress/data'; +import { createRegistrySelector } from '@wordpress/data'; import deprecated from '@wordpress/deprecated'; /** @@ -16,19 +16,6 @@ import deprecated from '@wordpress/deprecated'; import { REDUCER_KEY } from './name'; import { getQueriedItems } from './queried-data'; -/** - * Returns true if resolution is in progress for the core selector of the given - * name and arguments. - * - * @param {string} selectorName Core data selector name. - * @param {...*} args Arguments passed to selector. - * - * @return {boolean} Whether resolution is in progress. - */ -function isResolving( selectorName, ...args ) { - return select( 'core/data' ).isResolving( REDUCER_KEY, selectorName, args ); -} - /** * Returns true if a request is in progress for embed preview data, or false * otherwise. @@ -38,9 +25,9 @@ function isResolving( selectorName, ...args ) { * * @return {boolean} Whether a request is in progress for an embed preview. */ -export function isRequestingEmbedPreview( state, url ) { - return isResolving( 'getEmbedPreview', url ); -} +export const isRequestingEmbedPreview = createRegistrySelector( ( registry ) => ( state, url ) => { + return registry.select( 'core/data' ).isResolving( REDUCER_KEY, 'getEmbedPreview', [ url ] ); +} ); /** * Returns all available authors. diff --git a/packages/data/src/factory.js b/packages/data/src/factory.js new file mode 100644 index 0000000000000..866ce64052839 --- /dev/null +++ b/packages/data/src/factory.js @@ -0,0 +1,12 @@ +/** + * Mark a function as a registry selector. + * + * @param {function} registrySelector Function receiving a registry object and returning a state selector. + * + * @return {function} marked registry selector. + */ +export function createRegistrySelector( registrySelector ) { + registrySelector.isRegistrySelector = true; + + return registrySelector; +} diff --git a/packages/data/src/index.js b/packages/data/src/index.js index 6574f002d47e4..a5d1a51214654 100644 --- a/packages/data/src/index.js +++ b/packages/data/src/index.js @@ -15,6 +15,7 @@ export { default as RegistryProvider, RegistryConsumer } from './components/regi export { default as __experimentalAsyncModeProvider } from './components/async-mode-provider'; export { createRegistry } from './registry'; export { plugins }; +export { createRegistrySelector } from './factory'; /** * The combineReducers helper function turns an object whose values are different diff --git a/packages/data/src/namespace-store.js b/packages/data/src/namespace-store.js index dc0c0075fd620..2e5f2b3022a3f 100644 --- a/packages/data/src/namespace-store.js +++ b/packages/data/src/namespace-store.js @@ -19,7 +19,7 @@ import createResolversCacheMiddleware from './resolvers-cache-middleware'; * * @param {string} key Identifying string used for namespace and redex dev tools. * @param {Object} options Contains reducer, actions, selectors, and resolvers. - * @param {Object} registry Temporary registry reference, required for namespace updates. + * @param {Object} registry Registry reference. * * @return {Object} Store Object. */ @@ -32,7 +32,7 @@ export default function createNamespace( key, options, registry ) { actions = mapActions( options.actions, store ); } if ( options.selectors ) { - selectors = mapSelectors( options.selectors, store ); + selectors = mapSelectors( options.selectors, store, registry ); } if ( options.resolvers ) { const fulfillment = getCoreDataFulfillment( registry, key ); @@ -100,10 +100,14 @@ function createReduxStore( reducer, key, registry ) { * public facing API. Selectors will get passed the * state as first argument. * @param {Object} store The redux store to which the selectors should be mapped. + * @param {Object} registry Registry reference. + * * @return {Object} Selectors mapped to the redux store provided. */ -function mapSelectors( selectors, store ) { - const createStateSelector = ( selector ) => function runSelector() { +function mapSelectors( selectors, store, registry ) { + const createStateSelector = ( registeredSelector ) => function runSelector() { + const selector = registeredSelector.isRegistrySelector ? registeredSelector( registry ) : registeredSelector; + // This function is an optimized implementation of: // // selector( store.getState(), ...arguments ) diff --git a/packages/data/src/test/registry.js b/packages/data/src/test/registry.js index 70dc39fae0a07..e85495240e1f3 100644 --- a/packages/data/src/test/registry.js +++ b/packages/data/src/test/registry.js @@ -7,6 +7,7 @@ import { castArray, mapValues } from 'lodash'; * Internal dependencies */ import { createRegistry } from '../registry'; +import { createRegistrySelector } from '../factory'; describe( 'createRegistry', () => { let registry; @@ -441,6 +442,27 @@ describe( 'createRegistry', () => { expect( registry.select( 'reducer1' ).selector2() ).toEqual( 'result2' ); expect( selector2 ).toBeCalledWith( store.getState() ); } ); + + it( 'should run the registry selectors properly', () => { + const selector1 = () => 'result1'; + const selector2 = createRegistrySelector( ( reg ) => () => + reg.select( 'reducer1' ).selector1() + ); + registry.registerStore( 'reducer1', { + reducer: () => 'state1', + selectors: { + selector1, + }, + } ); + registry.registerStore( 'reducer2', { + reducer: () => 'state1', + selectors: { + selector2, + }, + } ); + + expect( registry.select( 'reducer2' ).selector2() ).toEqual( 'result1' ); + } ); } ); describe( 'subscribe', () => {