@wordpress/data 6.9.0 → 6.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +16 -9
- package/build/components/use-select/index.js +27 -17
- package/build/components/use-select/index.js.map +1 -1
- package/build/components/with-registry/index.js.map +1 -1
- package/build/controls.js.map +1 -1
- package/build/plugins/persistence/index.js.map +1 -1
- package/build/redux-store/index.js +14 -7
- package/build/redux-store/index.js.map +1 -1
- package/build/redux-store/metadata/utils.js.map +1 -1
- package/build/resolvers-cache-middleware.js.map +1 -1
- package/build/store/index.js.map +1 -1
- package/build-module/components/use-select/index.js +27 -17
- package/build-module/components/use-select/index.js.map +1 -1
- package/build-module/components/with-registry/index.js.map +1 -1
- package/build-module/controls.js.map +1 -1
- package/build-module/plugins/persistence/index.js.map +1 -1
- package/build-module/redux-store/index.js +14 -7
- package/build-module/redux-store/index.js.map +1 -1
- package/build-module/redux-store/metadata/utils.js.map +1 -1
- package/build-module/resolvers-cache-middleware.js.map +1 -1
- package/build-module/store/index.js.map +1 -1
- package/build-types/redux-store/metadata/utils.d.ts.map +1 -1
- package/build-types/types.d.ts +18 -1
- package/build-types/types.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/components/use-select/index.js +24 -17
- package/src/components/use-select/test/suspense.js +15 -11
- package/src/components/with-dispatch/test/index.js +4 -5
- package/src/components/with-registry/index.js +8 -7
- package/src/components/with-select/test/index.js +12 -18
- package/src/controls.js +16 -11
- package/src/plugins/persistence/index.js +2 -4
- package/src/redux-store/index.js +22 -12
- package/src/redux-store/metadata/test/utils.js +1 -2
- package/src/redux-store/metadata/utils.ts +24 -24
- package/src/redux-store/test/index.js +4 -3
- package/src/resolvers-cache-middleware.js +33 -34
- package/src/store/index.js +10 -6
- package/src/test/registry.js +19 -23
- package/src/types.ts +39 -6
- package/tsconfig.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/data",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.12.0",
|
|
4
4
|
"description": "Data module for WordPress.",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -28,12 +28,12 @@
|
|
|
28
28
|
"sideEffects": false,
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@babel/runtime": "^7.16.0",
|
|
31
|
-
"@wordpress/compose": "^5.
|
|
32
|
-
"@wordpress/deprecated": "^3.
|
|
33
|
-
"@wordpress/element": "^4.
|
|
34
|
-
"@wordpress/is-shallow-equal": "^4.
|
|
35
|
-
"@wordpress/priority-queue": "^2.
|
|
36
|
-
"@wordpress/redux-routine": "^4.
|
|
31
|
+
"@wordpress/compose": "^5.10.0",
|
|
32
|
+
"@wordpress/deprecated": "^3.12.0",
|
|
33
|
+
"@wordpress/element": "^4.10.0",
|
|
34
|
+
"@wordpress/is-shallow-equal": "^4.12.0",
|
|
35
|
+
"@wordpress/priority-queue": "^2.12.0",
|
|
36
|
+
"@wordpress/redux-routine": "^4.12.0",
|
|
37
37
|
"equivalent-key-map": "^0.2.2",
|
|
38
38
|
"is-promise": "^4.0.0",
|
|
39
39
|
"lodash": "^4.17.21",
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"publishConfig": {
|
|
48
48
|
"access": "public"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "a80eeb62ec7cb1418b9915c277e084a29d6665e3"
|
|
51
51
|
}
|
|
@@ -20,7 +20,19 @@ import useAsyncMode from '../async-mode-provider/use-async-mode';
|
|
|
20
20
|
const noop = () => {};
|
|
21
21
|
const renderQueue = createQueue();
|
|
22
22
|
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* @typedef {import('../../types').StoreDescriptor<C>} StoreDescriptor
|
|
25
|
+
* @template C
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* @typedef {import('../../types').ReduxStoreConfig<State,Actions,Selectors>} ReduxStoreConfig
|
|
29
|
+
* @template State,Actions,Selectors
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* @typedef {import('../../types').UseSelectReturn<T>} UseSelectReturn
|
|
33
|
+
* @template T
|
|
34
|
+
*/
|
|
35
|
+
/** @typedef {import('../../types').MapSelect} MapSelect */
|
|
24
36
|
|
|
25
37
|
/**
|
|
26
38
|
* Custom react hook for retrieving props from registered selectors.
|
|
@@ -28,20 +40,16 @@ const renderQueue = createQueue();
|
|
|
28
40
|
* In general, this custom React hook follows the
|
|
29
41
|
* [rules of hooks](https://reactjs.org/docs/hooks-rules.html).
|
|
30
42
|
*
|
|
31
|
-
* @
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* element tree.
|
|
42
|
-
* @param {Array} deps If provided, this memoizes the mapSelect so the
|
|
43
|
-
* same `mapSelect` is invoked on every state
|
|
44
|
-
* change unless the dependencies change.
|
|
43
|
+
* @template {MapSelect | StoreDescriptor<any>} T
|
|
44
|
+
* @param {T} mapSelect Function called on every state change. The returned value is
|
|
45
|
+
* exposed to the component implementing this hook. The function
|
|
46
|
+
* receives the `registry.select` method on the first argument
|
|
47
|
+
* and the `registry` on the second argument.
|
|
48
|
+
* When a store key is passed, all selectors for the store will be
|
|
49
|
+
* returned. This is only meant for usage of these selectors in event
|
|
50
|
+
* callbacks, not for data needed to create the element tree.
|
|
51
|
+
* @param {unknown[]} deps If provided, this memoizes the mapSelect so the same `mapSelect` is
|
|
52
|
+
* invoked on every state change unless the dependencies change.
|
|
45
53
|
*
|
|
46
54
|
* @example
|
|
47
55
|
* ```js
|
|
@@ -86,8 +94,7 @@ const renderQueue = createQueue();
|
|
|
86
94
|
* return <div onPaste={ onPaste }>{ children }</div>;
|
|
87
95
|
* }
|
|
88
96
|
* ```
|
|
89
|
-
*
|
|
90
|
-
* @return {Function} A custom react hook.
|
|
97
|
+
* @return {UseSelectReturn<T>} A custom react hook.
|
|
91
98
|
*/
|
|
92
99
|
export default function useSelect( mapSelect, deps ) {
|
|
93
100
|
const hasMappingFunction = 'function' === typeof mapSelect;
|
|
@@ -50,17 +50,21 @@ function createRegistryWithStore() {
|
|
|
50
50
|
const sleep = ( ms ) => new Promise( ( r ) => setTimeout( () => r(), ms ) );
|
|
51
51
|
|
|
52
52
|
const resolvers = {
|
|
53
|
-
getToken:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
53
|
+
getToken:
|
|
54
|
+
() =>
|
|
55
|
+
async ( { dispatch } ) => {
|
|
56
|
+
await sleep( 10 );
|
|
57
|
+
dispatch( { type: 'RECEIVE_TOKEN', token: 'token' } );
|
|
58
|
+
},
|
|
59
|
+
getData:
|
|
60
|
+
( token ) =>
|
|
61
|
+
async ( { dispatch } ) => {
|
|
62
|
+
await sleep( 10 );
|
|
63
|
+
if ( ! token ) {
|
|
64
|
+
throw 'missing token in resolver';
|
|
65
|
+
}
|
|
66
|
+
dispatch( { type: 'RECEIVE_DATA', data: 'therealdata' } );
|
|
67
|
+
},
|
|
64
68
|
getThatFails: () => async () => {
|
|
65
69
|
await sleep( 10 );
|
|
66
70
|
throw 'resolution failed';
|
|
@@ -57,8 +57,8 @@ describe( 'withDispatch', () => {
|
|
|
57
57
|
} );
|
|
58
58
|
const testInstance = testRenderer.root;
|
|
59
59
|
|
|
60
|
-
const incrementBeforeSetProps =
|
|
61
|
-
.props.onClick;
|
|
60
|
+
const incrementBeforeSetProps =
|
|
61
|
+
testInstance.findByType( 'button' ).props.onClick;
|
|
62
62
|
|
|
63
63
|
// Verify that dispatch respects props at the time of being invoked by
|
|
64
64
|
// changing props after the initial mount.
|
|
@@ -194,9 +194,8 @@ describe( 'withDispatch', () => {
|
|
|
194
194
|
);
|
|
195
195
|
} );
|
|
196
196
|
|
|
197
|
-
const counterUpdateHandler =
|
|
198
|
-
'button'
|
|
199
|
-
).props.onClick;
|
|
197
|
+
const counterUpdateHandler =
|
|
198
|
+
testRenderer.root.findByType( 'button' ).props.onClick;
|
|
200
199
|
|
|
201
200
|
act( () => {
|
|
202
201
|
counterUpdateHandler();
|
|
@@ -17,13 +17,14 @@ import { RegistryConsumer } from '../registry-provider';
|
|
|
17
17
|
* @return {WPComponent} Enhanced component.
|
|
18
18
|
*/
|
|
19
19
|
const withRegistry = createHigherOrderComponent(
|
|
20
|
-
( OriginalComponent ) => ( props ) =>
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
( OriginalComponent ) => ( props ) =>
|
|
21
|
+
(
|
|
22
|
+
<RegistryConsumer>
|
|
23
|
+
{ ( registry ) => (
|
|
24
|
+
<OriginalComponent { ...props } registry={ registry } />
|
|
25
|
+
) }
|
|
26
|
+
</RegistryConsumer>
|
|
27
|
+
),
|
|
27
28
|
'withRegistry'
|
|
28
29
|
);
|
|
29
30
|
|
|
@@ -50,9 +50,8 @@ describe( 'withSelect', () => {
|
|
|
50
50
|
.fn()
|
|
51
51
|
.mockImplementation( ( props ) => <div>{ props.data }</div> );
|
|
52
52
|
|
|
53
|
-
const DataBoundComponent =
|
|
54
|
-
OriginalComponent
|
|
55
|
-
);
|
|
53
|
+
const DataBoundComponent =
|
|
54
|
+
withSelect( mapSelectToProps )( OriginalComponent );
|
|
56
55
|
let testRenderer;
|
|
57
56
|
act( () => {
|
|
58
57
|
testRenderer = TestRenderer.create(
|
|
@@ -268,9 +267,8 @@ describe( 'withSelect', () => {
|
|
|
268
267
|
.fn()
|
|
269
268
|
.mockImplementation( ( props ) => <div>{ props.count }</div> );
|
|
270
269
|
|
|
271
|
-
const DataBoundComponent =
|
|
272
|
-
OriginalComponent
|
|
273
|
-
);
|
|
270
|
+
const DataBoundComponent =
|
|
271
|
+
withSelect( mapSelectToProps )( OriginalComponent );
|
|
274
272
|
|
|
275
273
|
let testRenderer;
|
|
276
274
|
act( () => {
|
|
@@ -367,9 +365,8 @@ describe( 'withSelect', () => {
|
|
|
367
365
|
|
|
368
366
|
const OriginalComponent = jest.fn().mockImplementation( () => <div /> );
|
|
369
367
|
|
|
370
|
-
const DataBoundComponent =
|
|
371
|
-
OriginalComponent
|
|
372
|
-
);
|
|
368
|
+
const DataBoundComponent =
|
|
369
|
+
withSelect( mapSelectToProps )( OriginalComponent );
|
|
373
370
|
|
|
374
371
|
act( () => {
|
|
375
372
|
TestRenderer.create(
|
|
@@ -492,9 +489,8 @@ describe( 'withSelect', () => {
|
|
|
492
489
|
<div>{ JSON.stringify( props ) }</div>
|
|
493
490
|
) );
|
|
494
491
|
|
|
495
|
-
const DataBoundComponent =
|
|
496
|
-
OriginalComponent
|
|
497
|
-
);
|
|
492
|
+
const DataBoundComponent =
|
|
493
|
+
withSelect( mapSelectToProps )( OriginalComponent );
|
|
498
494
|
|
|
499
495
|
let testRenderer;
|
|
500
496
|
act( () => {
|
|
@@ -561,9 +557,8 @@ describe( 'withSelect', () => {
|
|
|
561
557
|
<div>{ props.count || 'Unknown' }</div>
|
|
562
558
|
) );
|
|
563
559
|
|
|
564
|
-
const DataBoundComponent =
|
|
565
|
-
OriginalComponent
|
|
566
|
-
);
|
|
560
|
+
const DataBoundComponent =
|
|
561
|
+
withSelect( mapSelectToProps )( OriginalComponent );
|
|
567
562
|
|
|
568
563
|
let testRenderer;
|
|
569
564
|
act( () => {
|
|
@@ -691,9 +686,8 @@ describe( 'withSelect', () => {
|
|
|
691
686
|
.fn()
|
|
692
687
|
.mockImplementation( ( props ) => <div>{ props.value }</div> );
|
|
693
688
|
|
|
694
|
-
const DataBoundComponent =
|
|
695
|
-
OriginalComponent
|
|
696
|
-
);
|
|
689
|
+
const DataBoundComponent =
|
|
690
|
+
withSelect( mapSelectToProps )( OriginalComponent );
|
|
697
691
|
|
|
698
692
|
let testRenderer;
|
|
699
693
|
act( () => {
|
package/src/controls.js
CHANGED
|
@@ -118,20 +118,25 @@ export const controls = { select, resolveSelect, dispatch };
|
|
|
118
118
|
|
|
119
119
|
export const builtinControls = {
|
|
120
120
|
[ SELECT ]: createRegistryControl(
|
|
121
|
-
( registry ) =>
|
|
122
|
-
|
|
121
|
+
( registry ) =>
|
|
122
|
+
( { storeKey, selectorName, args } ) =>
|
|
123
|
+
registry.select( storeKey )[ selectorName ]( ...args )
|
|
123
124
|
),
|
|
124
125
|
[ RESOLVE_SELECT ]: createRegistryControl(
|
|
125
|
-
( registry ) =>
|
|
126
|
-
|
|
127
|
-
.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
126
|
+
( registry ) =>
|
|
127
|
+
( { storeKey, selectorName, args } ) => {
|
|
128
|
+
const method = registry.select( storeKey )[ selectorName ]
|
|
129
|
+
.hasResolver
|
|
130
|
+
? 'resolveSelect'
|
|
131
|
+
: 'select';
|
|
132
|
+
return registry[ method ]( storeKey )[ selectorName ](
|
|
133
|
+
...args
|
|
134
|
+
);
|
|
135
|
+
}
|
|
132
136
|
),
|
|
133
137
|
[ DISPATCH ]: createRegistryControl(
|
|
134
|
-
( registry ) =>
|
|
135
|
-
|
|
138
|
+
( registry ) =>
|
|
139
|
+
( { storeKey, actionName, args } ) =>
|
|
140
|
+
registry.dispatch( storeKey )[ actionName ]( ...args )
|
|
136
141
|
),
|
|
137
142
|
};
|
|
@@ -63,10 +63,8 @@ export const withLazySameState = ( reducer ) => ( state, action ) => {
|
|
|
63
63
|
* @return {Object} Persistence interface.
|
|
64
64
|
*/
|
|
65
65
|
export function createPersistenceInterface( options ) {
|
|
66
|
-
const {
|
|
67
|
-
|
|
68
|
-
storageKey = DEFAULT_STORAGE_KEY,
|
|
69
|
-
} = options;
|
|
66
|
+
const { storage = DEFAULT_STORAGE, storageKey = DEFAULT_STORAGE_KEY } =
|
|
67
|
+
options;
|
|
70
68
|
|
|
71
69
|
let data;
|
|
72
70
|
|
package/src/redux-store/index.js
CHANGED
|
@@ -23,8 +23,14 @@ import * as metadataSelectors from './metadata/selectors';
|
|
|
23
23
|
import * as metadataActions from './metadata/actions';
|
|
24
24
|
|
|
25
25
|
/** @typedef {import('../types').DataRegistry} DataRegistry */
|
|
26
|
-
/**
|
|
27
|
-
|
|
26
|
+
/**
|
|
27
|
+
* @typedef {import('../types').StoreDescriptor<C>} StoreDescriptor
|
|
28
|
+
* @template C
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* @typedef {import('../types').ReduxStoreConfig<State,Actions,Selectors>} ReduxStoreConfig
|
|
32
|
+
* @template State,Actions,Selectors
|
|
33
|
+
*/
|
|
28
34
|
|
|
29
35
|
const trimUndefinedValues = ( array ) => {
|
|
30
36
|
const result = [ ...array ];
|
|
@@ -83,12 +89,13 @@ function createResolversCache() {
|
|
|
83
89
|
* } );
|
|
84
90
|
* ```
|
|
85
91
|
*
|
|
86
|
-
* @
|
|
87
|
-
* @param {
|
|
88
|
-
*
|
|
89
|
-
*
|
|
92
|
+
* @template State,Actions,Selectors
|
|
93
|
+
* @param {string} key Unique namespace identifier.
|
|
94
|
+
* @param {ReduxStoreConfig<State,Actions,Selectors>} options Registered store options, with properties
|
|
95
|
+
* describing reducer, actions, selectors,
|
|
96
|
+
* and resolvers.
|
|
90
97
|
*
|
|
91
|
-
* @return
|
|
98
|
+
* @return {StoreDescriptor<ReduxStoreConfig<State,Actions,Selectors>>} Store Object.
|
|
92
99
|
*/
|
|
93
100
|
export default function createReduxStore( key, options ) {
|
|
94
101
|
return {
|
|
@@ -136,8 +143,9 @@ export default function createReduxStore( key, options ) {
|
|
|
136
143
|
{
|
|
137
144
|
...mapValues(
|
|
138
145
|
metadataSelectors,
|
|
139
|
-
( selector ) =>
|
|
140
|
-
|
|
146
|
+
( selector ) =>
|
|
147
|
+
( state, ...args ) =>
|
|
148
|
+
selector( state.metadata, ...args )
|
|
141
149
|
),
|
|
142
150
|
...mapValues( options.selectors, ( selector ) => {
|
|
143
151
|
if ( selector.isRegistrySelector ) {
|
|
@@ -308,9 +316,11 @@ function mapSelectors( selectors, store ) {
|
|
|
308
316
|
* @return {Object} Actions mapped to the redux store provided.
|
|
309
317
|
*/
|
|
310
318
|
function mapActions( actions, store ) {
|
|
311
|
-
const createBoundAction =
|
|
312
|
-
|
|
313
|
-
|
|
319
|
+
const createBoundAction =
|
|
320
|
+
( action ) =>
|
|
321
|
+
( ...args ) => {
|
|
322
|
+
return Promise.resolve( store.dispatch( action( ...args ) ) );
|
|
323
|
+
};
|
|
314
324
|
|
|
315
325
|
return mapValues( actions, createBoundAction );
|
|
316
326
|
}
|
|
@@ -47,8 +47,7 @@ describe( 'selectorArgsToStateKey', () => {
|
|
|
47
47
|
|
|
48
48
|
it( 'should remove trailing undefined values', () => {
|
|
49
49
|
expect( selectorArgsToStateKey( [ 1, 2, undefined ] ) ).toEqual( [
|
|
50
|
-
1,
|
|
51
|
-
2,
|
|
50
|
+
1, 2,
|
|
52
51
|
] );
|
|
53
52
|
expect(
|
|
54
53
|
selectorArgsToStateKey( [ 1, 2, undefined, undefined ] )
|
|
@@ -10,33 +10,33 @@ import type { AnyAction, Reducer } from 'redux';
|
|
|
10
10
|
* @param actionProperty Action property by which to key object.
|
|
11
11
|
* @return Higher-order reducer.
|
|
12
12
|
*/
|
|
13
|
-
export const onSubKey =
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
) => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
13
|
+
export const onSubKey =
|
|
14
|
+
< TState extends unknown, TAction extends AnyAction >(
|
|
15
|
+
actionProperty: string
|
|
16
|
+
) =>
|
|
17
|
+
(
|
|
18
|
+
reducer: Reducer< TState, TAction >
|
|
19
|
+
): Reducer< Record< string, TState >, TAction > =>
|
|
20
|
+
( state: Record< string, TState > = {}, action ) => {
|
|
21
|
+
// Retrieve subkey from action. Do not track if undefined; useful for cases
|
|
22
|
+
// where reducer is scoped by action shape.
|
|
23
|
+
const key = action[ actionProperty ];
|
|
24
|
+
if ( key === undefined ) {
|
|
25
|
+
return state;
|
|
26
|
+
}
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
// Avoid updating state if unchanged. Note that this also accounts for a
|
|
29
|
+
// reducer which returns undefined on a key which is not yet tracked.
|
|
30
|
+
const nextKeyState = reducer( state[ key ], action );
|
|
31
|
+
if ( nextKeyState === state[ key ] ) {
|
|
32
|
+
return state;
|
|
33
|
+
}
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
return {
|
|
36
|
+
...state,
|
|
37
|
+
[ key ]: nextKeyState,
|
|
38
|
+
};
|
|
38
39
|
};
|
|
39
|
-
};
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
42
|
* Normalize selector argument array by defaulting `undefined` value to an empty array
|
|
@@ -32,9 +32,10 @@ describe( 'controls', () => {
|
|
|
32
32
|
},
|
|
33
33
|
controls: {
|
|
34
34
|
DISPATCH: createRegistryControl(
|
|
35
|
-
( reg ) =>
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
( reg ) =>
|
|
36
|
+
( { store, action } ) => {
|
|
37
|
+
return reg.dispatch( store )[ action ]();
|
|
38
|
+
}
|
|
38
39
|
),
|
|
39
40
|
},
|
|
40
41
|
} );
|
|
@@ -20,42 +20,41 @@ import coreDataStore from './store';
|
|
|
20
20
|
*
|
|
21
21
|
* @return {Function} Middleware function.
|
|
22
22
|
*/
|
|
23
|
-
const createResolversCacheMiddleware =
|
|
24
|
-
next
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if ( ! resolver || ! resolver.shouldInvalidate ) {
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
resolversByArgs.forEach( ( value, args ) => {
|
|
40
|
-
// resolversByArgs is the map Map([ args ] => boolean) storing the cache resolution status for a given selector.
|
|
41
|
-
// If the value is "finished" or "error" it means this resolver has finished its resolution which means we need
|
|
42
|
-
// to invalidate it, if it's true it means it's inflight and the invalidation is not necessary.
|
|
43
|
-
if (
|
|
44
|
-
( value?.status !== 'finished' &&
|
|
45
|
-
value?.status !== 'error' ) ||
|
|
46
|
-
! resolver.shouldInvalidate( action, ...args )
|
|
47
|
-
) {
|
|
23
|
+
const createResolversCacheMiddleware =
|
|
24
|
+
( registry, reducerKey ) => () => ( next ) => ( action ) => {
|
|
25
|
+
const resolvers = registry
|
|
26
|
+
.select( coreDataStore )
|
|
27
|
+
.getCachedResolvers( reducerKey );
|
|
28
|
+
Object.entries( resolvers ).forEach(
|
|
29
|
+
( [ selectorName, resolversByArgs ] ) => {
|
|
30
|
+
const resolver = get( registry.stores, [
|
|
31
|
+
reducerKey,
|
|
32
|
+
'resolvers',
|
|
33
|
+
selectorName,
|
|
34
|
+
] );
|
|
35
|
+
if ( ! resolver || ! resolver.shouldInvalidate ) {
|
|
48
36
|
return;
|
|
49
37
|
}
|
|
38
|
+
resolversByArgs.forEach( ( value, args ) => {
|
|
39
|
+
// resolversByArgs is the map Map([ args ] => boolean) storing the cache resolution status for a given selector.
|
|
40
|
+
// If the value is "finished" or "error" it means this resolver has finished its resolution which means we need
|
|
41
|
+
// to invalidate it, if it's true it means it's inflight and the invalidation is not necessary.
|
|
42
|
+
if (
|
|
43
|
+
( value?.status !== 'finished' &&
|
|
44
|
+
value?.status !== 'error' ) ||
|
|
45
|
+
! resolver.shouldInvalidate( action, ...args )
|
|
46
|
+
) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
50
49
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
};
|
|
50
|
+
// Trigger cache invalidation
|
|
51
|
+
registry
|
|
52
|
+
.dispatch( coreDataStore )
|
|
53
|
+
.invalidateResolution( reducerKey, selectorName, args );
|
|
54
|
+
} );
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
return next( action );
|
|
58
|
+
};
|
|
60
59
|
|
|
61
60
|
export default createResolversCacheMiddleware;
|
package/src/store/index.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
const coreDataStore = {
|
|
2
2
|
name: 'core/data',
|
|
3
3
|
instantiate( registry ) {
|
|
4
|
-
const getCoreDataSelector =
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
const getCoreDataSelector =
|
|
5
|
+
( selectorName ) =>
|
|
6
|
+
( key, ...args ) => {
|
|
7
|
+
return registry.select( key )[ selectorName ]( ...args );
|
|
8
|
+
};
|
|
7
9
|
|
|
8
|
-
const getCoreDataAction =
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
const getCoreDataAction =
|
|
11
|
+
( actionName ) =>
|
|
12
|
+
( key, ...args ) => {
|
|
13
|
+
return registry.dispatch( key )[ actionName ]( ...args );
|
|
14
|
+
};
|
|
11
15
|
|
|
12
16
|
return {
|
|
13
17
|
getSelectors() {
|
package/src/test/registry.js
CHANGED
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* External dependencies
|
|
3
|
-
*/
|
|
4
|
-
import { castArray, mapValues } from 'lodash';
|
|
5
|
-
|
|
6
1
|
/**
|
|
7
2
|
* Internal dependencies
|
|
8
3
|
*/
|
|
@@ -30,7 +25,7 @@ describe( 'createRegistry', () => {
|
|
|
30
25
|
return unsubscribe;
|
|
31
26
|
}
|
|
32
27
|
function subscribeUntil( predicates ) {
|
|
33
|
-
predicates =
|
|
28
|
+
predicates = Array.from( predicates );
|
|
34
29
|
|
|
35
30
|
return new Promise( ( resolve ) => {
|
|
36
31
|
subscribeWithUnsubscribe( () => {
|
|
@@ -553,8 +548,8 @@ describe( 'createRegistry', () => {
|
|
|
553
548
|
|
|
554
549
|
it( 'should run the registry selectors properly', () => {
|
|
555
550
|
const selector1 = () => 'result1';
|
|
556
|
-
const selector2 = createRegistrySelector(
|
|
557
|
-
select( 'reducer1' ).selector1()
|
|
551
|
+
const selector2 = createRegistrySelector(
|
|
552
|
+
( select ) => () => select( 'reducer1' ).selector1()
|
|
558
553
|
);
|
|
559
554
|
registry.registerStore( 'reducer1', {
|
|
560
555
|
reducer: () => 'state1',
|
|
@@ -576,8 +571,8 @@ describe( 'createRegistry', () => {
|
|
|
576
571
|
|
|
577
572
|
it( 'should run the registry selector from a non-registry selector', () => {
|
|
578
573
|
const selector1 = () => 'result1';
|
|
579
|
-
const selector2 = createRegistrySelector(
|
|
580
|
-
select( 'reducer1' ).selector1()
|
|
574
|
+
const selector2 = createRegistrySelector(
|
|
575
|
+
( select ) => () => select( 'reducer1' ).selector1()
|
|
581
576
|
);
|
|
582
577
|
const selector3 = () => selector2();
|
|
583
578
|
registry.registerStore( 'reducer1', {
|
|
@@ -656,9 +651,8 @@ describe( 'createRegistry', () => {
|
|
|
656
651
|
const secondListener = jest.fn();
|
|
657
652
|
|
|
658
653
|
subscribeWithUnsubscribe( firstListener );
|
|
659
|
-
const secondUnsubscribe =
|
|
660
|
-
secondListener
|
|
661
|
-
);
|
|
654
|
+
const secondUnsubscribe =
|
|
655
|
+
subscribeWithUnsubscribe( secondListener );
|
|
662
656
|
|
|
663
657
|
store.dispatch( { type: 'dummy' } );
|
|
664
658
|
|
|
@@ -750,16 +744,18 @@ describe( 'createRegistry', () => {
|
|
|
750
744
|
// representation of the object, the latter applying its
|
|
751
745
|
// function proxying.
|
|
752
746
|
expect( _registry ).toMatchObject(
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
747
|
+
Object.fromEntries(
|
|
748
|
+
Object.entries( registry ).map( ( [ key ] ) => {
|
|
749
|
+
if ( key === 'stores' ) {
|
|
750
|
+
return [ key, expect.any( Object ) ];
|
|
751
|
+
}
|
|
752
|
+
// TODO: Remove this after namsespaces is removed.
|
|
753
|
+
if ( key === 'namespaces' ) {
|
|
754
|
+
return [ key, registry.stores ];
|
|
755
|
+
}
|
|
756
|
+
return [ key, expect.any( Function ) ];
|
|
757
|
+
} )
|
|
758
|
+
)
|
|
763
759
|
);
|
|
764
760
|
|
|
765
761
|
actualOptions = options;
|