@@ -63,7 +63,9 @@ export function useRetry(options: UseRetryOptions): UseRetryReturn {
63
63
const [ isRetrying , setIsRetrying ] = useState ( false ) ;
64
64
const [ currentDelay , setCurrentDelay ] = useState < number | null > ( null ) ;
65
65
const [ attemptCount , setAttemptCount ] = useState ( 0 ) ;
66
- const [ timeUntilNextRetry , setTimeUntilNextRetry ] = useState < number | null > ( null ) ;
66
+ const [ timeUntilNextRetry , setTimeUntilNextRetry ] = useState < number | null > (
67
+ null ,
68
+ ) ;
67
69
const [ isManualRetry , setIsManualRetry ] = useState ( false ) ;
68
70
69
71
const timeoutRef = useRef < number | null > ( null ) ;
@@ -84,10 +86,13 @@ export function useRetry(options: UseRetryOptions): UseRetryReturn {
84
86
startTimeRef . current = null ;
85
87
} , [ ] ) ;
86
88
87
- const calculateDelay = useCallback ( ( attempt : number ) : number => {
88
- const delay = initialDelay * Math . pow ( multiplier , attempt ) ;
89
- return Math . min ( delay , maxDelay ) ;
90
- } , [ initialDelay , multiplier , maxDelay ] ) ;
89
+ const calculateDelay = useCallback (
90
+ ( attempt : number ) : number => {
91
+ const delay = initialDelay * multiplier ** attempt ;
92
+ return Math . min ( delay , maxDelay ) ;
93
+ } ,
94
+ [ initialDelay , multiplier , maxDelay ] ,
95
+ ) ;
91
96
92
97
const performRetry = useCallback ( async ( ) => {
93
98
setIsRetrying ( true ) ;
@@ -103,47 +108,56 @@ export function useRetry(options: UseRetryOptions): UseRetryReturn {
103
108
setIsManualRetry ( false ) ;
104
109
} catch ( error ) {
105
110
// If retry fails, schedule next attempt (if not manual and under max attempts)
106
- setAttemptCount ( prev => prev + 1 ) ;
111
+ setAttemptCount ( ( prev ) => prev + 1 ) ;
107
112
setIsRetrying ( false ) ;
108
113
setIsManualRetry ( false ) ;
109
114
}
110
115
} , [ onRetryEvent , clearTimers ] ) ;
111
116
112
- const scheduleNextRetry = useCallback ( ( attempt : number ) => {
113
- if ( attempt >= maxAttempts ) {
114
- return ;
115
- }
117
+ const scheduleNextRetry = useCallback (
118
+ ( attempt : number ) => {
119
+ if ( attempt >= maxAttempts ) {
120
+ return ;
121
+ }
116
122
117
- const delay = calculateDelay ( attempt ) ;
118
- setCurrentDelay ( delay ) ;
119
- setTimeUntilNextRetry ( delay ) ;
120
- startTimeRef . current = Date . now ( ) ;
121
-
122
- // Start countdown timer
123
- countdownRef . current = setInterval ( ( ) => {
124
- if ( startTimeRef . current ) {
125
- const elapsed = Date . now ( ) - startTimeRef . current ;
126
- const remaining = Math . max ( 0 , delay - elapsed ) ;
127
- setTimeUntilNextRetry ( remaining ) ;
128
-
129
- if ( remaining <= 0 ) {
130
- if ( countdownRef . current ) {
131
- clearInterval ( countdownRef . current ) ;
132
- countdownRef . current = null ;
123
+ // Calculate delay based on attempt - 2 (so second attempt gets initialDelay)
124
+ const delay = calculateDelay ( Math . max ( 0 , attempt - 2 ) ) ;
125
+ setCurrentDelay ( delay ) ;
126
+ setTimeUntilNextRetry ( delay ) ;
127
+ startTimeRef . current = Date . now ( ) ;
128
+
129
+ // Start countdown timer
130
+ countdownRef . current = setInterval ( ( ) => {
131
+ if ( startTimeRef . current ) {
132
+ const elapsed = Date . now ( ) - startTimeRef . current ;
133
+ const remaining = Math . max ( 0 , delay - elapsed ) ;
134
+ setTimeUntilNextRetry ( remaining ) ;
135
+
136
+ if ( remaining <= 0 ) {
137
+ if ( countdownRef . current ) {
138
+ clearInterval ( countdownRef . current ) ;
139
+ countdownRef . current = null ;
140
+ }
133
141
}
134
142
}
135
- }
136
- } , 100 ) ; // Update every 100ms for smooth countdown
143
+ } , 100 ) ; // Update every 100ms for smooth countdown
137
144
138
- // Schedule the actual retry
139
- timeoutRef . current = setTimeout ( ( ) => {
140
- performRetry ( ) ;
141
- } , delay ) ;
142
- } , [ calculateDelay , maxAttempts , performRetry ] ) ;
145
+ // Schedule the actual retry
146
+ timeoutRef . current = setTimeout ( ( ) => {
147
+ performRetry ( ) ;
148
+ } , delay ) ;
149
+ } ,
150
+ [ calculateDelay , maxAttempts , performRetry ] ,
151
+ ) ;
143
152
144
153
// Effect to schedule next retry after a failed attempt
145
154
useEffect ( ( ) => {
146
- if ( ! isRetrying && ! isManualRetry && attemptCount > 0 && attemptCount < maxAttempts ) {
155
+ if (
156
+ ! isRetrying &&
157
+ ! isManualRetry &&
158
+ attemptCount > 1 &&
159
+ attemptCount <= maxAttempts
160
+ ) {
147
161
scheduleNextRetry ( attemptCount ) ;
148
162
}
149
163
} , [ attemptCount , isRetrying , isManualRetry , maxAttempts , scheduleNextRetry ] ) ;
@@ -157,8 +171,10 @@ export function useRetry(options: UseRetryOptions): UseRetryReturn {
157
171
} , [ clearTimers , performRetry ] ) ;
158
172
159
173
const startRetrying = useCallback ( ( ) => {
160
- setAttemptCount ( 1 ) ; // This will trigger the first retry attempt
161
- } , [ ] ) ;
174
+ // Immediately perform the first retry attempt
175
+ setAttemptCount ( 1 ) ;
176
+ performRetry ( ) ;
177
+ } , [ performRetry ] ) ;
162
178
163
179
const stopRetrying = useCallback ( ( ) => {
164
180
clearTimers ( ) ;
0 commit comments