diff --git a/packages/data/README.md b/packages/data/README.md index 66bdc2faa5b42..c496d0ef6dbf0 100644 --- a/packages/data/README.md +++ b/packages/data/README.md @@ -297,6 +297,7 @@ configurations. _Parameters_ - _storeConfigs_ `Object`: Initial store configurations. +- _parent_ `?Object`: Parent registry. _Returns_ diff --git a/packages/data/src/registry.js b/packages/data/src/registry.js index e1c324f6ef8ac..15f02180c7b85 100644 --- a/packages/data/src/registry.js +++ b/packages/data/src/registry.js @@ -34,11 +34,12 @@ import createCoreDataStore from './store'; * Creates a new store registry, given an optional object of initial store * configurations. * - * @param {Object} storeConfigs Initial store configurations. + * @param {Object} storeConfigs Initial store configurations. + * @param {Object?} parent Parent registry. * * @return {WPDataRegistry} Data registry. */ -export function createRegistry( storeConfigs = {} ) { +export function createRegistry( storeConfigs = {}, parent = null ) { const stores = {}; let listeners = []; @@ -74,7 +75,11 @@ export function createRegistry( storeConfigs = {} ) { */ function select( reducerKey ) { const store = stores[ reducerKey ]; - return store && store.getSelectors(); + if ( store ) { + return store.getSelectors(); + } + + return parent && parent.select( reducerKey ); } /** @@ -87,7 +92,11 @@ export function createRegistry( storeConfigs = {} ) { */ function dispatch( reducerKey ) { const store = stores[ reducerKey ]; - return store && store.getActions(); + if ( store ) { + return store.getActions(); + } + + return parent && parent.dispatch( reducerKey ); } // @@ -172,5 +181,9 @@ export function createRegistry( storeConfigs = {} ) { ( [ name, config ] ) => registry.registerStore( name, config ) ); + if ( parent ) { + parent.subscribe( globalListener ); + } + return withPlugins( registry ); } diff --git a/packages/data/src/test/registry.js b/packages/data/src/test/registry.js index cd18ac2d89285..b828cd0199159 100644 --- a/packages/data/src/test/registry.js +++ b/packages/data/src/test/registry.js @@ -604,4 +604,52 @@ describe( 'createRegistry', () => { expect( registry.select() ).toBe( 10 ); } ); } ); + + describe( 'parent registry', () => { + it( 'should call parent registry selectors/actions if defined', () => { + const mySelector = jest.fn(); + const myAction = jest.fn(); + const getSelectors = () => ( { mySelector } ); + const getActions = () => ( { myAction } ); + const subscribe = () => {}; + registry.registerGenericStore( 'store', { getSelectors, getActions, subscribe } ); + const subRegistry = createRegistry( {}, registry ); + + subRegistry.select( 'store' ).mySelector(); + subRegistry.dispatch( 'store' ).myAction(); + + expect( mySelector ).toHaveBeenCalled(); + expect( myAction ).toHaveBeenCalled(); + } ); + + it( 'should override existing store in parent registry', () => { + const mySelector = jest.fn(); + const myAction = jest.fn(); + const getSelectors = () => ( { mySelector } ); + const getActions = () => ( { myAction } ); + const subscribe = () => {}; + registry.registerGenericStore( 'store', { getSelectors, getActions, subscribe } ); + + const subRegistry = createRegistry( {}, registry ); + const mySelector2 = jest.fn(); + const myAction2 = jest.fn(); + const getSelectors2 = () => ( { mySelector: mySelector2 } ); + const getActions2 = () => ( { myAction: myAction2 } ); + const subscribe2 = () => {}; + subRegistry.registerGenericStore( 'store', { + getSelectors: getSelectors2, + getActions: getActions2, + subscribe: subscribe2, + } ); + + subRegistry.select( 'store' ).mySelector(); + subRegistry.dispatch( 'store' ).myAction(); + + expect( mySelector ).not.toHaveBeenCalled(); + expect( myAction ).not.toHaveBeenCalled(); + + expect( mySelector2 ).toHaveBeenCalled(); + expect( myAction2 ).toHaveBeenCalled(); + } ); + } ); } );