Skip to content

Commit 4dcd304

Browse files
committed
fix(useWorkerLoad): group error and retry into an optional attr
1 parent fd8ef72 commit 4dcd304

File tree

2 files changed

+56
-19
lines changed

2 files changed

+56
-19
lines changed

src/__tests__/useWorkerLoad.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ it('stops loading on failure and returns the error', async () => {
9292

9393
await waitForNextUpdate();
9494

95-
expect(result.current.error).toBe(thrownError);
95+
expect(result.current.error?.value).toBe(thrownError);
96+
expect(result.current.error?.retry).not.toBeUndefined();
9697
expect(result.current.isLoading).toEqual(false);
9798
});
9899

@@ -119,7 +120,8 @@ it('can set error', async () => {
119120
result.current.setError(thrownError);
120121
});
121122

122-
expect(result.current.error).toEqual(thrownError);
123+
expect(result.current.error?.value).toEqual(thrownError);
124+
expect(result.current.error?.retry).not.toBeUndefined();
123125
});
124126

125127
it('can set isLoading', async () => {
@@ -138,6 +140,7 @@ it('can set isLoading', async () => {
138140

139141
describe('retry', () => {
140142
it('sets loading true', async () => {
143+
callbackFn.mockRejectedValue(thrownError);
141144
const { result, waitForNextUpdate } = renderHook(useHookHelper, {
142145
initialProps,
143146
});
@@ -146,7 +149,7 @@ describe('retry', () => {
146149
expect(result.current.isLoading).toBe(false);
147150

148151
act(() => {
149-
result.current.retry();
152+
result.current.error!.retry();
150153
});
151154

152155
expect(result.current.isLoading).toBe(true);
@@ -162,9 +165,9 @@ describe('retry', () => {
162165
});
163166

164167
await waitForNextUpdate();
165-
expect(result.current.error).toBe(thrownError);
168+
expect(result.current.error?.value).toBe(thrownError);
166169

167-
await act(result.current.retry);
170+
await act(result.current.error!.retry);
168171

169172
expect(result.current.error).toBeUndefined();
170173
});
@@ -179,19 +182,22 @@ describe('retry', () => {
179182
});
180183

181184
await waitForNextUpdate();
182-
expect(result.current.error).toBe(thrownError);
185+
expect(result.current.error?.value).toBe(thrownError);
183186
expect(result.current.data).toBeUndefined();
184187

185-
await act(result.current.retry);
188+
await act(result.current.error!.retry);
186189

187190
expect(result.current.data).toBe(val);
191+
expect(result.current.error).toBeUndefined();
188192
});
189193
});
190194

191195
/// These tests won't fail their execution, but the type-checking instead.
192196
describe('test types', () => {
193197
type Assert<T, Expected> = T extends Expected
194-
? (Expected extends T ? true : never)
198+
? Expected extends T
199+
? true
200+
: never
195201
: never;
196202

197203
describe('`initialValue` is unset', () => {

src/index.tsx

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,41 @@ import {
77
MutableRefObject,
88
} from 'react';
99

10+
/**
11+
* The return of a [[useWorkerLoad]] call.
12+
*
13+
* See [[RetryWorkerError]] for errors.
14+
*
15+
* @typeparam Data The worker's return type
16+
*/
17+
interface WorkerLoad<Data> {
18+
/** Indicates if the worker is running */
19+
isLoading: boolean;
20+
21+
/** The worker's returned value stored in a state */
22+
data: Data;
23+
24+
/** An optional object that contains any thrown errors, if any, and a retry function */
25+
error?: RetryWorkerError;
26+
27+
/** Sets [[isLoading]] state manually */
28+
setIsLoading: (_: boolean) => void;
29+
30+
/** Sets [[error]] state manually */
31+
setError: (_: Error | undefined) => void;
32+
}
33+
34+
/**
35+
* Encapsulates [[useWorkerLoad]]'s errors and retry function
36+
*/
37+
interface RetryWorkerError {
38+
/** The error thrown by the worker's call */
39+
value: Error;
40+
41+
/** Calls the worker again */
42+
retry: () => Promise<void>;
43+
}
44+
1045
/**
1146
* Executes an asynchronous effect
1247
*
@@ -44,6 +79,7 @@ export const useAsyncLayoutEffect = (
4479
*
4580
* @param worker The callback function that runs a promise.
4681
* @param dependencies The callback dependencies.
82+
* @category Workers
4783
*/
4884
export const useWorker = <TArgs extends readonly any[], TRet>(
4985
worker: (...args: TArgs) => Promise<TRet>,
@@ -180,15 +216,6 @@ export const useLazyRef = <T extends any>(
180216
return ref as MutableRefObject<T>;
181217
};
182218

183-
type WorkerLoad<Data> = {
184-
isLoading: boolean;
185-
setIsLoading: (_: boolean) => void;
186-
setError: (_: Error | undefined) => void;
187-
error: Error | undefined;
188-
data: Data;
189-
retry: () => Promise<void>;
190-
};
191-
192219
export function useWorkerLoad<Data>(
193220
worker: () => Promise<Data | undefined>,
194221
): WorkerLoad<Data | undefined>;
@@ -205,6 +232,8 @@ export function useWorkerLoad<Data>(
205232
*
206233
* @param worker An asynchronous function that returns data, which is saved into a state
207234
* @param initialValue The data's initial value
235+
* @typeparam Data The worker's return type
236+
* @category Workers
208237
*/
209238
export function useWorkerLoad<Data>(
210239
worker: () => Promise<typeof initialValue>,
@@ -227,9 +256,11 @@ export function useWorkerLoad<Data>(
227256
return {
228257
data,
229258
isLoading,
230-
error,
231259
setIsLoading,
232260
setError,
233-
retry: callback,
261+
error: error && {
262+
value: error,
263+
retry: callback,
264+
},
234265
};
235266
}

0 commit comments

Comments
 (0)