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 );