diff --git a/data/README.md b/data/README.md index 74b30566ae6e8a..32522d178e9e6f 100644 --- a/data/README.md +++ b/data/README.md @@ -39,14 +39,14 @@ Let's say the state of our plugin (registered with the key `myPlugin`) has the f wp.data.registerSelectors( 'myPlugin', { getTitle: ( state ) => state.title } ); ``` -### `wp.data.select( key: string, selectorName: string, ...args )` +### `wp.data.select( key: string )` -This function allows calling any registered selector. Given a module's key, a selector's name and extra arguments passed to the selector, this function calls the selector passing it the current state and the extra arguments provided. +This function allows calling any registered selector. Given a module's key, this function returns an object of all selector functions registered for the module. #### Example: ```js -wp.data.select( 'myPlugin', 'getTitle' ); // Returns "My post title" +wp.data.select( 'myPlugin' ).getTitle(); // Returns "My post title" ``` ### `wp.data.query( mapSelectorsToProps: function )( WrappedComponent: Component )` @@ -58,7 +58,7 @@ const Component = ( { title } ) =>
{ title }
; wp.data.query( select => { return { - title: select( 'myPlugin', 'getTitle' ), + title: select( 'myPlugin' ).getTitle(), }; } )( Component ); ``` @@ -71,7 +71,7 @@ Function used to subscribe to data changes. The listener function is called each // Subscribe. const unsubscribe = wp.data.subscribe( () => { const data = { - slug: wp.data.select( 'core/editor', 'getEditedPostSlug' ), + slug: wp.data.select( 'core/editor' ).getEditedPostSlug(), }; console.log( 'data changed', data ); diff --git a/data/index.js b/data/index.js index 676f5d7eaef4d9..4730b9c7850ee8 100644 --- a/data/index.js +++ b/data/index.js @@ -69,7 +69,32 @@ export function registerReducer( reducerKey, reducer ) { * state as first argument. */ export function registerSelectors( reducerKey, newSelectors ) { - selectors[ reducerKey ] = newSelectors; + const store = stores[ reducerKey ]; + const createStateSelector = ( selector ) => ( ...args ) => selector( store.getState(), ...args ); + selectors[ reducerKey ] = mapValues( newSelectors, createStateSelector ); +} + +/** + * Calls a selector given the current state and extra arguments. + * + * @param {string} reducerKey Part of the state shape to register the + * selectors for. + * + * @return {*} The selector's returned value. + */ +export function select( reducerKey ) { + if ( arguments.length > 1 ) { + // eslint-disable-next-line no-console + console.warn( + 'Deprecated: `select` now accepts only a single argument: the reducer key. ' + + 'The return value is an object of selector functions.' + ); + + const [ , selectorKey, ...args ] = arguments; + return select( reducerKey )[ selectorKey ]( ...args ); + } + + return selectors[ reducerKey ]; } /** @@ -100,24 +125,6 @@ export const query = ( mapSelectorsToProps ) => ( WrappedComponent ) => { }; return connectWithStore( ( state, ownProps ) => { - const select = ( key, selectorName, ...args ) => { - return selectors[ key ][ selectorName ]( state[ key ], ...args ); - }; - return mapSelectorsToProps( select, ownProps ); } ); }; - -/** - * Calls a selector given the current state and extra arguments. - * - * @param {string} reducerKey Part of the state shape to register the - * selectors for. - * @param {string} selectorName Selector name. - * @param {*} args Selectors arguments. - * - * @return {*} The selector's returned value. - */ -export const select = ( reducerKey, selectorName, ...args ) => { - return selectors[ reducerKey ][ selectorName ]( stores[ reducerKey ].getState(), ...args ); -}; diff --git a/data/test/index.js b/data/test/index.js index dc8e81bd5be80c..dfafb0e286f057 100644 --- a/data/test/index.js +++ b/data/test/index.js @@ -32,12 +32,23 @@ describe( 'select', () => { selector2, } ); - expect( select( 'reducer1', 'selector1' ) ).toEqual( 'result1' ); + expect( select( 'reducer1' ).selector1() ).toEqual( 'result1' ); expect( selector1 ).toBeCalledWith( store.getState() ); - expect( select( 'reducer1', 'selector2' ) ).toEqual( 'result2' ); + expect( select( 'reducer1' ).selector2() ).toEqual( 'result2' ); expect( selector2 ).toBeCalledWith( store.getState() ); } ); + + it( 'provides upgrade path for deprecated usage', () => { + const store = registerReducer( 'reducer', () => 'state' ); + const selector = jest.fn( () => 'result' ); + + registerSelectors( 'reducer', { selector } ); + + expect( select( 'reducer', 'selector', 'arg' ) ).toEqual( 'result' ); + expect( selector ).toBeCalledWith( store.getState(), 'arg' ); + expect( console ).toHaveWarned(); + } ); } ); describe( 'query', () => { @@ -48,7 +59,7 @@ describe( 'query', () => { } ); const Component = query( ( selectFunc, ownProps ) => { return { - data: selectFunc( 'reactReducer', 'reactSelector', ownProps.keyName ), + data: selectFunc( 'reactReducer' ).reactSelector( ownProps.keyName ), }; } )( ( props ) => { return
{ props.data }
; @@ -68,7 +79,7 @@ describe( 'subscribe', () => { globalSelector: ( state ) => state, } ); const unsubscribe = subscribe( () => { - incrementedValue = select( 'myAwesomeReducer', 'globalSelector' ); + incrementedValue = select( 'myAwesomeReducer' ).globalSelector(); } ); const action = { type: 'dummy' }; diff --git a/edit-post/components/sidebar/featured-image/index.js b/edit-post/components/sidebar/featured-image/index.js index 9263b8614aa3df..9edd0aa8aa926a 100644 --- a/edit-post/components/sidebar/featured-image/index.js +++ b/edit-post/components/sidebar/featured-image/index.js @@ -43,7 +43,7 @@ function FeaturedImage( { isOpened, postType, onTogglePanel } ) { } const applyQuery = query( ( select ) => ( { - postTypeSlug: select( 'core/editor', 'getEditedPostAttribute', 'type' ), + postTypeSlug: select( 'core/editor' ).getEditedPostAttribute( 'type' ), } ) ); const applyConnect = connect( diff --git a/edit-post/components/sidebar/header.js b/edit-post/components/sidebar/header.js index 62201a9952a7b2..790f7c7517d229 100644 --- a/edit-post/components/sidebar/header.js +++ b/edit-post/components/sidebar/header.js @@ -49,7 +49,7 @@ const SidebarHeader = ( { panel, onSetPanel, onToggleSidebar, count } ) => { export default compose( query( ( select ) => ( { - count: select( 'core/editor', 'getSelectedBlockCount' ), + count: select( 'core/editor' ).getSelectedBlockCount(), } ) ), connect( ( state ) => ( { diff --git a/edit-post/components/sidebar/page-attributes/index.js b/edit-post/components/sidebar/page-attributes/index.js index d20573e1441888..87e01ca8b18708 100644 --- a/edit-post/components/sidebar/page-attributes/index.js +++ b/edit-post/components/sidebar/page-attributes/index.js @@ -46,7 +46,7 @@ export function PageAttributes( { isOpened, onTogglePanel, postType } ) { } const applyQuery = query( ( select ) => ( { - postTypeSlug: select( 'core/editor', 'getEditedPostAttribute', 'type' ), + postTypeSlug: select( 'core/editor' ).getEditedPostAttribute( 'type' ), } ) ); const applyConnect = connect( diff --git a/editor/hooks/copy-content/index.js b/editor/hooks/copy-content/index.js index 7a80c271a7ce99..e72c9ea1aab121 100644 --- a/editor/hooks/copy-content/index.js +++ b/editor/hooks/copy-content/index.js @@ -24,7 +24,7 @@ function CopyContentButton( { editedPostContent, hasCopied, setState } ) { const Enhanced = compose( query( ( select ) => ( { - editedPostContent: select( 'core/editor', 'getEditedPostAttribute', 'content' ), + editedPostContent: select( 'core/editor' ).getEditedPostAttribute( 'content' ), } ) ), withState( { hasCopied: false } ) )( CopyContentButton );