Skip to content

Commit 1192816

Browse files
committed
memoize returned execute() fn + minor refactors
1 parent 0e34040 commit 1192816

File tree

1 file changed

+18
-13
lines changed

1 file changed

+18
-13
lines changed

src/index.ts

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,17 @@ const useIsomorphicLayoutEffect =
1414
? useLayoutEffect
1515
: useEffect;
1616

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.
1818
// This way we are sure to always get latest value provided to hook and
1919
// avoid weird issues due to closures capturing stale values...
20+
// See https://github.com/facebook/react/issues/16956
2021
// See https://overreacted.io/making-setinterval-declarative-with-react-hooks/
2122
const useGetter = <T>(t: T) => {
2223
const ref = useRef(t);
2324
useIsomorphicLayoutEffect(() => {
2425
ref.current = t;
2526
});
26-
return () => ref.current;
27+
return useCallback(() => ref.current, [ref]);
2728
};
2829

2930
type UnknownResult = unknown;
@@ -164,19 +165,18 @@ const useAsyncState = <R extends {}>(
164165
[value, setValue]
165166
);
166167

167-
const set = setValue;
168-
169168
const merge = useCallback(
170169
(state: Partial<AsyncState<R>>) =>
171-
set({
170+
setValue({
172171
...value,
173172
...state,
174173
}),
175-
[value, set]
174+
[value, setValue]
176175
);
176+
177177
return {
178178
value,
179-
set,
179+
set: setValue,
180180
merge,
181181
reset,
182182
setLoading,
@@ -276,23 +276,28 @@ const useAsyncInternal = <R = UnknownResult, Args extends any[] = UnknownArgs>(
276276
}
277277
};
278278

279+
const getLatestExecuteAsyncOperation = useGetter(executeAsyncOperation);
280+
281+
const executeAsyncOperationMemo: (...args: Args) => Promise<R> = useCallback(
282+
(...args) => getLatestExecuteAsyncOperation()(...args),
283+
[getLatestExecuteAsyncOperation]
284+
);
285+
279286
// Keep this outside useEffect, because inside isMounted()
280287
// will be true as the component is already mounted when it's run
281288
const isMounting = !isMounted();
282289
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();
288293
}, params);
289294

290295
return {
291296
...AsyncState.value,
292297
set: AsyncState.set,
293298
merge: AsyncState.merge,
294299
reset: AsyncState.reset,
295-
execute: executeAsyncOperation,
300+
execute: executeAsyncOperationMemo,
296301
currentPromise: CurrentPromise.get(),
297302
currentParams,
298303
};

0 commit comments

Comments
 (0)