diff --git a/src/use-retry-fn/index.ts b/src/use-retry-fn/index.ts index c45a75f5..c9070623 100644 --- a/src/use-retry-fn/index.ts +++ b/src/use-retry-fn/index.ts @@ -1,7 +1,7 @@ -import { useRef } from 'react' import { useCreation } from '../use-creation' import { useLatest } from '../use-latest' import { useStableFn } from '../use-stable-fn' +import { useVersionedAction } from '../use-versioned-action' import { isFunction, wait } from '../utils/basic' import type { AnyFunc } from '../utils/basic' @@ -67,7 +67,7 @@ export function defaultRetryInterval(currentCount: number) { export function useRetryFn(fn: T, options: UseRetryFnOptions = {}): T { const { count = 3, interval = defaultRetryInterval, onError, onErrorRetry, onRetryFailed } = options - const version = useRef(0) + const [incVersion, runVersionedAction] = useVersionedAction() const latest = useLatest({ fn, @@ -78,56 +78,48 @@ export function useRetryFn(fn: T, options: UseRetryF onRetryFailed, }) - const runFnWithRetry = useCreation(() => { - const retryFn = async ( - retryState: UseRetryFnRetryState, - ...args: Parameters - ): Promise> | undefined> => { - try { - const result = await latest.current.fn(...args) + const runFnWithRetry = useCreation( + () => + async (retryState: UseRetryFnRetryState, ...args: Parameters): Promise> | undefined> => { + try { + const result = await latest.current.fn(...args) - if (retryState.version !== version.current) { - return result - } - - retryState.currentCount = 0 - - return result - } catch (error) { - if (retryState.version !== version.current) { - return - } - - retryState.currentCount++ + runVersionedAction(retryState.version, () => { + retryState.currentCount = 0 + }) - const { onError, onErrorRetry, onRetryFailed, interval } = latest.current + return result + } catch (error) { + return runVersionedAction(retryState.version, async () => { + retryState.currentCount++ - onError?.(error as E | undefined) + const { onError, onErrorRetry, onRetryFailed, interval } = latest.current - if (retryState.currentCount > retryState.retryCount) { - onRetryFailed?.(error as E | undefined, { ...retryState }) - retryState.currentCount = 0 - return - } + onError?.(error as E | undefined) - const nextInterval = isFunction(interval) ? interval(retryState.currentCount) : interval + if (retryState.currentCount > retryState.retryCount) { + onRetryFailed?.(error as E | undefined, { ...retryState }) + retryState.currentCount = 0 + return + } - await wait(nextInterval) + const nextInterval = isFunction(interval) ? interval(retryState.currentCount) : interval - onErrorRetry?.(error as E | undefined, { ...retryState }) + await wait(nextInterval) - return retryFn(retryState, ...args) - } - } + onErrorRetry?.(error as E | undefined, { ...retryState }) - return retryFn - }) + return runFnWithRetry({ ...retryState }, ...args) + }) + } + }, + ) const fnWithRetry = useStableFn(((...args: Parameters) => { const retryState = { currentCount: 0, retryCount: latest.current.count, - version: ++version.current, + version: incVersion(), } return runFnWithRetry(retryState, ...args)