Enhance useCollection for conditionally returning previous results (https://github.com/woocommerce/woocommerce-blocks/pull/1182)
* add new config to `useCollection` options for controlling whether to invoke select or not. also adds tests. * update inline docs
This commit is contained in:
parent
47e082ef58
commit
b4df4e056c
|
@ -35,7 +35,7 @@ class TestErrorBoundary extends ReactComponent {
|
|||
}
|
||||
}
|
||||
|
||||
describe( 'useStoreProducts', () => {
|
||||
describe( 'useCollection', () => {
|
||||
let registry, mocks, renderer;
|
||||
const getProps = ( testRenderer ) => {
|
||||
const { results, isLoading } = testRenderer.root.findByType(
|
||||
|
@ -233,4 +233,65 @@ describe( 'useStoreProducts', () => {
|
|||
renderer.unmount();
|
||||
}
|
||||
);
|
||||
it( 'should return previous query results if `shouldSelect` is false', () => {
|
||||
mocks.selectors.getCollection.mockImplementation(
|
||||
( state, ...args ) => {
|
||||
return args;
|
||||
}
|
||||
);
|
||||
const TestComponent = getTestComponent();
|
||||
act( () => {
|
||||
renderer = TestRenderer.create(
|
||||
getWrappedComponents( TestComponent, {
|
||||
options: {
|
||||
namespace: 'test/store',
|
||||
resourceName: 'products',
|
||||
resourceValues: [ 10, 20 ],
|
||||
},
|
||||
} )
|
||||
);
|
||||
} );
|
||||
const { results } = getProps( renderer );
|
||||
// rerender but with shouldSelect to false
|
||||
act( () => {
|
||||
renderer.update(
|
||||
getWrappedComponents( TestComponent, {
|
||||
options: {
|
||||
namespace: 'test/store',
|
||||
resourceName: 'productsb',
|
||||
resourceValues: [ 10, 30 ],
|
||||
shouldSelect: false,
|
||||
},
|
||||
} )
|
||||
);
|
||||
} );
|
||||
const { results: results2 } = getProps( renderer );
|
||||
expect( results2 ).toBe( results );
|
||||
// expect 2 calls because internally, useSelect invokes callback twice
|
||||
// on mount.
|
||||
expect( mocks.selectors.getCollection ).toHaveBeenCalledTimes( 2 );
|
||||
|
||||
// rerender again but set shouldSelect to true again and we should see
|
||||
// new results
|
||||
act( () => {
|
||||
renderer.update(
|
||||
getWrappedComponents( TestComponent, {
|
||||
options: {
|
||||
namespace: 'test/store',
|
||||
resourceName: 'productsb',
|
||||
resourceValues: [ 10, 30 ],
|
||||
shouldSelect: true,
|
||||
},
|
||||
} )
|
||||
);
|
||||
} );
|
||||
const { results: results3 } = getProps( renderer );
|
||||
expect( results3 ).not.toEqual( results );
|
||||
expect( results3 ).toEqual( [
|
||||
'test/store',
|
||||
'productsb',
|
||||
{},
|
||||
[ 10, 30 ],
|
||||
] );
|
||||
} );
|
||||
} );
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
import { COLLECTIONS_STORE_KEY as storeKey } from '@woocommerce/block-data';
|
||||
import { useSelect } from '@wordpress/data';
|
||||
import { useRef } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
|
@ -29,6 +30,9 @@ import { useShallowEqual } from './use-shallow-equal';
|
|||
* query to execute on the collection
|
||||
* (optional). Example:
|
||||
* `{ order: 'ASC', order_by: 'price' }`
|
||||
* @param {boolean} options.shouldSelect If false, the previous results will be
|
||||
* returned and internal selects will not
|
||||
* fire.
|
||||
*
|
||||
* @return {Object} This hook will return an object with two properties:
|
||||
* - results An array of collection items returned.
|
||||
|
@ -41,6 +45,7 @@ export const useCollection = ( options ) => {
|
|||
resourceName,
|
||||
resourceValues = [],
|
||||
query = {},
|
||||
shouldSelect = true,
|
||||
} = options;
|
||||
if ( ! namespace || ! resourceName ) {
|
||||
throw new Error(
|
||||
|
@ -48,11 +53,15 @@ export const useCollection = ( options ) => {
|
|||
'the resource properties.'
|
||||
);
|
||||
}
|
||||
const currentResults = useRef( { results: [], isLoading: true } );
|
||||
// ensure we feed the previous reference if it's equivalent
|
||||
const currentQuery = useShallowEqual( query );
|
||||
const currentResourceValues = useShallowEqual( resourceValues );
|
||||
const { results = [], isLoading = true } = useSelect(
|
||||
const results = useSelect(
|
||||
( select ) => {
|
||||
if ( ! shouldSelect ) {
|
||||
return null;
|
||||
}
|
||||
const store = select( storeKey );
|
||||
// filter out query if it is undefined.
|
||||
const args = [
|
||||
|
@ -69,10 +78,18 @@ export const useCollection = ( options ) => {
|
|||
),
|
||||
};
|
||||
},
|
||||
[ namespace, resourceName, currentResourceValues, currentQuery ]
|
||||
[
|
||||
namespace,
|
||||
resourceName,
|
||||
currentResourceValues,
|
||||
currentQuery,
|
||||
shouldSelect,
|
||||
]
|
||||
);
|
||||
return {
|
||||
results,
|
||||
isLoading,
|
||||
};
|
||||
// if selector was not bailed, then update current results. Otherwise return
|
||||
// previous results
|
||||
if ( results !== null ) {
|
||||
currentResults.current = results;
|
||||
}
|
||||
return currentResults.current;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue