@@ -23,6 +23,7 @@ import { getDataProviderCallArguments } from './getDataProviderCallArguments';
23
23
// These calls get replayed once the dataProvider exits optimistic mode
24
24
const optimisticCalls = [ ] ;
25
25
const undoableOptimisticCalls = [ ] ;
26
+ let nbRemainingOptimisticCalls = 0 ;
26
27
27
28
/**
28
29
* Hook for getting a dataProvider
@@ -190,7 +191,13 @@ const useDataProvider = (): DataProviderProxy => {
190
191
} else {
191
192
optimisticCalls . push ( params ) ;
192
193
}
193
- return Promise . resolve ( ) ;
194
+ nbRemainingOptimisticCalls ++ ;
195
+ // Return a Promise that only resolves when the optimistic call was made
196
+ // otherwise hooks like useQueryWithStore will return loaded = true
197
+ // before the content actually reaches the Redux store.
198
+ // But as we can't determine when this particular query was finished,
199
+ // the Promise resolves only when *all* optimistic queries are done.
200
+ return waitFor ( ( ) => nbRemainingOptimisticCalls === 0 ) ;
194
201
}
195
202
return doQuery ( params ) ;
196
203
} ;
@@ -201,6 +208,18 @@ const useDataProvider = (): DataProviderProxy => {
201
208
return dataProviderProxy ;
202
209
} ;
203
210
211
+ // get a Promise that resolves after a delay in milliseconds
212
+ const later = ( delay = 100 ) : Promise < void > =>
213
+ new Promise ( function ( resolve ) {
214
+ setTimeout ( resolve , delay ) ;
215
+ } ) ;
216
+
217
+ // get a Promise that resolves once a condition is satisfied
218
+ const waitFor = ( condition : ( ) => boolean ) : Promise < void > =>
219
+ new Promise ( resolve =>
220
+ condition ( ) ? resolve ( ) : later ( ) . then ( ( ) => waitFor ( condition ) )
221
+ ) ;
222
+
204
223
const doQuery = ( {
205
224
type,
206
225
payload,
@@ -279,7 +298,7 @@ const performUndoableQuery = ({
279
298
dispatch,
280
299
logoutIfAccessDenied,
281
300
allArguments,
282
- } : QueryFunctionParams ) => {
301
+ } : QueryFunctionParams ) : Promise < { } > => {
283
302
dispatch ( startOptimisticMode ( ) ) ;
284
303
if ( window ) {
285
304
window . addEventListener ( 'beforeunload' , warnBeforeClosingWindow , {
@@ -419,18 +438,28 @@ const replayOptimisticCalls = async () => {
419
438
// We only handle all side effects queries if there are no more undoable queries
420
439
if ( undoableOptimisticCalls . length > 0 ) {
421
440
clone = [ ...undoableOptimisticCalls ] ;
441
+ // remove these calls from the list *before* doing them
442
+ // because side effects in the calls can add more calls
443
+ // so we don't want to erase these.
422
444
undoableOptimisticCalls . splice ( 0 , undoableOptimisticCalls . length ) ;
423
445
424
446
await Promise . all (
425
447
clone . map ( params => Promise . resolve ( doQuery . call ( null , params ) ) )
426
448
) ;
449
+ // once the calls are finished, decrease the number of remaining calls
450
+ nbRemainingOptimisticCalls -= clone . length ;
427
451
} else {
428
452
clone = [ ...optimisticCalls ] ;
453
+ // remove these calls from the list *before* doing them
454
+ // because side effects in the calls can add more calls
455
+ // so we don't want to erase these.
429
456
optimisticCalls . splice ( 0 , optimisticCalls . length ) ;
430
457
431
458
await Promise . all (
432
459
clone . map ( params => Promise . resolve ( doQuery . call ( null , params ) ) )
433
460
) ;
461
+ // once the calls are finished, decrease the number of remaining calls
462
+ nbRemainingOptimisticCalls -= clone . length ;
434
463
}
435
464
} ;
436
465
@@ -452,7 +481,7 @@ const performQuery = ({
452
481
dispatch,
453
482
logoutIfAccessDenied,
454
483
allArguments,
455
- } : QueryFunctionParams ) => {
484
+ } : QueryFunctionParams ) : Promise < any > => {
456
485
dispatch ( {
457
486
type : action ,
458
487
payload,
0 commit comments