@wordpress/data 8.6.0 → 9.1.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 +8 -0
- package/README.md +28 -65
- package/build/components/use-select/index.js +90 -55
- package/build/components/use-select/index.js.map +1 -1
- package/build/registry.js +16 -7
- package/build/registry.js.map +1 -1
- package/build-module/components/use-select/index.js +90 -55
- package/build-module/components/use-select/index.js.map +1 -1
- package/build-module/registry.js +16 -7
- package/build-module/registry.js.map +1 -1
- package/build-types/components/use-select/index.d.ts.map +1 -1
- package/build-types/registry.d.ts.map +1 -1
- package/package.json +9 -9
- package/src/components/use-select/index.js +87 -57
- package/src/components/use-select/test/index.js +247 -163
- package/src/registry.js +20 -8
- package/src/test/registry.js +31 -22
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -42,48 +42,85 @@ function Store( registry, suspense ) {
|
|
|
42
42
|
let lastMapResult;
|
|
43
43
|
let lastMapResultValid = false;
|
|
44
44
|
let lastIsAsync;
|
|
45
|
-
let
|
|
46
|
-
|
|
47
|
-
const createSubscriber = ( stores ) =>
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
45
|
+
let subscriber;
|
|
46
|
+
|
|
47
|
+
const createSubscriber = ( stores ) => {
|
|
48
|
+
// The set of stores the `subscribe` function is supposed to subscribe to. Here it is
|
|
49
|
+
// initialized, and then the `updateStores` function can add new stores to it.
|
|
50
|
+
const activeStores = [ ...stores ];
|
|
51
|
+
|
|
52
|
+
// The `subscribe` function, which is passed to the `useSyncExternalStore` hook, could
|
|
53
|
+
// be called multiple times to establish multiple subscriptions. That's why we need to
|
|
54
|
+
// keep a set of active subscriptions;
|
|
55
|
+
const activeSubscriptions = new Set();
|
|
56
|
+
|
|
57
|
+
function subscribe( listener ) {
|
|
58
|
+
// Invalidate the value right after subscription was created. React will
|
|
59
|
+
// call `getValue` after subscribing, to detect store updates that happened
|
|
60
|
+
// in the interval between the `getValue` call during render and creating
|
|
61
|
+
// the subscription, which is slightly delayed. We need to ensure that this
|
|
62
|
+
// second `getValue` call will compute a fresh value.
|
|
57
63
|
lastMapResultValid = false;
|
|
58
|
-
listener();
|
|
59
|
-
};
|
|
60
64
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
const onStoreChange = () => {
|
|
66
|
+
// Invalidate the value on store update, so that a fresh value is computed.
|
|
67
|
+
lastMapResultValid = false;
|
|
68
|
+
listener();
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const onChange = () => {
|
|
72
|
+
if ( lastIsAsync ) {
|
|
73
|
+
renderQueue.add( queueContext, onStoreChange );
|
|
74
|
+
} else {
|
|
75
|
+
onStoreChange();
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const unsubs = [];
|
|
80
|
+
function subscribeStore( storeName ) {
|
|
81
|
+
unsubs.push( registry.subscribe( onChange, storeName ) );
|
|
66
82
|
}
|
|
67
|
-
};
|
|
68
83
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
84
|
+
for ( const storeName of activeStores ) {
|
|
85
|
+
subscribeStore( storeName );
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
activeSubscriptions.add( subscribeStore );
|
|
89
|
+
|
|
90
|
+
return () => {
|
|
91
|
+
activeSubscriptions.delete( subscribeStore );
|
|
92
|
+
|
|
93
|
+
for ( const unsub of unsubs.values() ) {
|
|
94
|
+
// The return value of the subscribe function could be undefined if the store is a custom generic store.
|
|
95
|
+
unsub?.();
|
|
96
|
+
}
|
|
97
|
+
// Cancel existing store updates that were already scheduled.
|
|
98
|
+
renderQueue.cancel( queueContext );
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Check if `newStores` contains some stores we're not subscribed to yet, and add them.
|
|
103
|
+
function updateStores( newStores ) {
|
|
104
|
+
for ( const newStore of newStores ) {
|
|
105
|
+
if ( activeStores.includes( newStore ) ) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// New `subscribe` calls will subscribe to `newStore`, too.
|
|
110
|
+
activeStores.push( newStore );
|
|
72
111
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
112
|
+
// Add `newStore` to existing subscriptions.
|
|
113
|
+
for ( const subscription of activeSubscriptions ) {
|
|
114
|
+
subscription( newStore );
|
|
115
|
+
}
|
|
77
116
|
}
|
|
78
|
-
|
|
79
|
-
renderQueue.cancel( queueContext );
|
|
80
|
-
};
|
|
81
|
-
};
|
|
117
|
+
}
|
|
82
118
|
|
|
83
|
-
|
|
84
|
-
|
|
119
|
+
return { subscribe, updateStores };
|
|
120
|
+
};
|
|
85
121
|
|
|
86
|
-
|
|
122
|
+
return ( mapSelect, isAsync ) => {
|
|
123
|
+
function updateValue() {
|
|
87
124
|
// If the last value is valid, and the `mapSelect` callback hasn't changed,
|
|
88
125
|
// then we can safely return the cached value. The value can change only on
|
|
89
126
|
// store update, and in that case value will be invalidated by the listener.
|
|
@@ -91,19 +128,30 @@ function Store( registry, suspense ) {
|
|
|
91
128
|
return lastMapResult;
|
|
92
129
|
}
|
|
93
130
|
|
|
94
|
-
const
|
|
131
|
+
const listeningStores = { current: null };
|
|
132
|
+
const mapResult = registry.__unstableMarkListeningStores(
|
|
133
|
+
() => mapSelect( select, registry ),
|
|
134
|
+
listeningStores
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
if ( ! subscriber ) {
|
|
138
|
+
subscriber = createSubscriber( listeningStores.current );
|
|
139
|
+
} else {
|
|
140
|
+
subscriber.updateStores( listeningStores.current );
|
|
141
|
+
}
|
|
95
142
|
|
|
96
143
|
// If the new value is shallow-equal to the old one, keep the old one so
|
|
97
144
|
// that we don't trigger unwanted updates that do a `===` check.
|
|
98
145
|
if ( ! isShallowEqual( lastMapResult, mapResult ) ) {
|
|
99
146
|
lastMapResult = mapResult;
|
|
100
147
|
}
|
|
148
|
+
lastMapSelect = mapSelect;
|
|
101
149
|
lastMapResultValid = true;
|
|
102
150
|
}
|
|
103
151
|
|
|
104
152
|
function getValue() {
|
|
105
153
|
// Update the value in case it's been invalidated or `mapSelect` has changed.
|
|
106
|
-
updateValue(
|
|
154
|
+
updateValue();
|
|
107
155
|
return lastMapResult;
|
|
108
156
|
}
|
|
109
157
|
|
|
@@ -115,30 +163,12 @@ function Store( registry, suspense ) {
|
|
|
115
163
|
renderQueue.cancel( queueContext );
|
|
116
164
|
}
|
|
117
165
|
|
|
118
|
-
|
|
119
|
-
// changed and has dependencies.
|
|
120
|
-
// Usage without dependencies, `useSelect( ( s ) => { ... } )`, will subscribe
|
|
121
|
-
// only once, at mount, and won't resubscibe even if `mapSelect` changes.
|
|
122
|
-
if ( ! subscribe || ( resubscribe && mapSelect !== lastMapSelect ) ) {
|
|
123
|
-
// Find out what stores the `mapSelect` callback is selecting from and
|
|
124
|
-
// use that list to create subscriptions to specific stores.
|
|
125
|
-
const listeningStores = { current: null };
|
|
126
|
-
updateValue( () =>
|
|
127
|
-
registry.__unstableMarkListeningStores(
|
|
128
|
-
selectValue,
|
|
129
|
-
listeningStores
|
|
130
|
-
)
|
|
131
|
-
);
|
|
132
|
-
subscribe = createSubscriber( listeningStores.current );
|
|
133
|
-
} else {
|
|
134
|
-
updateValue( selectValue );
|
|
135
|
-
}
|
|
166
|
+
updateValue();
|
|
136
167
|
|
|
137
168
|
lastIsAsync = isAsync;
|
|
138
|
-
lastMapSelect = mapSelect;
|
|
139
169
|
|
|
140
170
|
// Return a pair of functions that can be passed to `useSyncExternalStore`.
|
|
141
|
-
return { subscribe, getValue };
|
|
171
|
+
return { subscribe: subscriber.subscribe, getValue };
|
|
142
172
|
};
|
|
143
173
|
}
|
|
144
174
|
|
|
@@ -151,7 +181,7 @@ function useMappingSelect( suspense, mapSelect, deps ) {
|
|
|
151
181
|
const isAsync = useAsyncMode();
|
|
152
182
|
const store = useMemo( () => Store( registry, suspense ), [ registry ] );
|
|
153
183
|
const selector = useCallback( mapSelect, deps );
|
|
154
|
-
const { subscribe, getValue } = store( selector,
|
|
184
|
+
const { subscribe, getValue } = store( selector, isAsync );
|
|
155
185
|
const result = useSyncExternalStore( subscribe, getValue, getValue );
|
|
156
186
|
useDebugValue( result );
|
|
157
187
|
return result;
|