@@ -14,16 +14,17 @@ const useIsomorphicLayoutEffect =
14
14
? useLayoutEffect
15
15
: useEffect ;
16
16
17
- // assign current value to a ref and providing a getter.
17
+ // Assign current value to a ref and returns a stable getter to get the latest value .
18
18
// This way we are sure to always get latest value provided to hook and
19
19
// avoid weird issues due to closures capturing stale values...
20
+ // See https://github.com/facebook/react/issues/16956
20
21
// See https://overreacted.io/making-setinterval-declarative-with-react-hooks/
21
22
const useGetter = < T > ( t : T ) => {
22
23
const ref = useRef ( t ) ;
23
24
useIsomorphicLayoutEffect ( ( ) => {
24
25
ref . current = t ;
25
26
} ) ;
26
- return ( ) => ref . current ;
27
+ return useCallback ( ( ) => ref . current , [ ref ] ) ;
27
28
} ;
28
29
29
30
type UnknownResult = unknown ;
@@ -164,19 +165,18 @@ const useAsyncState = <R extends {}>(
164
165
[ value , setValue ]
165
166
) ;
166
167
167
- const set = setValue ;
168
-
169
168
const merge = useCallback (
170
169
( state : Partial < AsyncState < R > > ) =>
171
- set ( {
170
+ setValue ( {
172
171
...value ,
173
172
...state ,
174
173
} ) ,
175
- [ value , set ]
174
+ [ value , setValue ]
176
175
) ;
176
+
177
177
return {
178
178
value,
179
- set,
179
+ set : setValue ,
180
180
merge,
181
181
reset,
182
182
setLoading,
@@ -276,23 +276,28 @@ const useAsyncInternal = <R = UnknownResult, Args extends any[] = UnknownArgs>(
276
276
}
277
277
} ;
278
278
279
+ const getLatestExecuteAsyncOperation = useGetter ( executeAsyncOperation ) ;
280
+
281
+ const executeAsyncOperationMemo : ( ...args : Args ) => Promise < R > = useCallback (
282
+ ( ...args ) => getLatestExecuteAsyncOperation ( ) ( ...args ) ,
283
+ [ getLatestExecuteAsyncOperation ]
284
+ ) ;
285
+
279
286
// Keep this outside useEffect, because inside isMounted()
280
287
// will be true as the component is already mounted when it's run
281
288
const isMounting = ! isMounted ( ) ;
282
289
useEffect ( ( ) => {
283
- if ( isMounting ) {
284
- normalizedOptions . executeOnMount && executeAsyncOperation ( ...params ) ;
285
- } else {
286
- normalizedOptions . executeOnUpdate && executeAsyncOperation ( ...params ) ;
287
- }
290
+ const execute = ( ) => getLatestExecuteAsyncOperation ( ) ( ...params ) ;
291
+ isMounting && normalizedOptions . executeOnMount && execute ( ) ;
292
+ ! isMounting && normalizedOptions . executeOnUpdate && execute ( ) ;
288
293
} , params ) ;
289
294
290
295
return {
291
296
...AsyncState . value ,
292
297
set : AsyncState . set ,
293
298
merge : AsyncState . merge ,
294
299
reset : AsyncState . reset ,
295
- execute : executeAsyncOperation ,
300
+ execute : executeAsyncOperationMemo ,
296
301
currentPromise : CurrentPromise . get ( ) ,
297
302
currentParams,
298
303
} ;
0 commit comments