@pixotope/query 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,30 +1,42 @@
1
1
  import { useCallback, useRef, useState } from "react";
2
2
 
3
- export type MutationFunction<TData = unknown, TParams = unknown> = (
4
- params: TParams,
5
- overrideTargetMachine?: string
6
- ) => Promise<TData>;
3
+ export type MutationFunction<
4
+ TData = unknown,
5
+ TParams = unknown,
6
+ TMetadata = unknown,
7
+ > = (params: TParams, meta?: TMetadata) => Promise<TData>;
7
8
 
8
9
  export interface MutationOptions<
9
10
  TData = unknown,
10
11
  TError = unknown,
11
12
  TParams = void,
13
+ TMetadata = unknown,
12
14
  > {
13
- mutationFn: MutationFunction<TData, TParams>;
15
+ mutationFn: MutationFunction<TData, TParams, TMetadata>;
14
16
  params?: TParams;
15
- onSuccess?: (data: TData, variables: TParams) => Promise<unknown> | unknown;
17
+ onSuccess?: (
18
+ data: TData,
19
+ variables: TParams,
20
+ meta?: TMetadata
21
+ ) => Promise<unknown> | unknown;
16
22
  onError?: (
17
23
  error: TMutationError<TError>,
18
- variables: TParams
24
+ variables: TParams,
25
+ meta?: TMetadata
19
26
  ) => Promise<unknown> | unknown;
20
27
  onSettled?: (
21
28
  data: TData | undefined,
22
29
  error: TMutationError<TError> | null,
23
- variables: TParams
30
+ variables: TParams,
31
+ meta?: TMetadata
24
32
  ) => Promise<unknown> | unknown;
25
33
  compareOrThrow?: (result: TData | TError) => boolean;
26
34
  timeout?: number;
27
- prepareParams?: (variables: TParams, defaults?: TParams) => TParams;
35
+ prepareParams?: (
36
+ variables: TParams,
37
+ defaults?: TParams,
38
+ meta?: TMetadata
39
+ ) => TParams;
28
40
  }
29
41
 
30
42
  type TMutationError<TError> = TError | Error | null;
@@ -33,13 +45,19 @@ export interface MutateOptions<
33
45
  TData = unknown,
34
46
  TError = unknown,
35
47
  TParams = void,
48
+ TMetadata = unknown,
36
49
  > {
37
- onSuccess?: (data: TData, variables: TParams) => void;
38
- onError?: (error: TMutationError<TError>, variables: TParams) => void;
50
+ onSuccess?: (data: TData, variables: TParams, meta?: TMetadata) => void;
51
+ onError?: (
52
+ error: TMutationError<TError>,
53
+ variables: TParams,
54
+ meta?: TMetadata
55
+ ) => void;
39
56
  onSettled?: (
40
57
  data: TData | undefined,
41
58
  error: TMutationError<TError> | null,
42
- variables: TParams
59
+ variables: TParams,
60
+ meta?: TMetadata
43
61
  ) => void;
44
62
  }
45
63
 
@@ -61,58 +79,13 @@ export class ComparisonFailError<TPayload = unknown> extends Error {
61
79
  }
62
80
  }
63
81
 
64
- /**
65
- * `useMutation` is a hook that allows you to perform a mutation/push updates to the services while
66
- * providing extensive API to tap into the status and results of the mutation.
67
- * @param mutationFn The mutation function to be called when the `mutate` function is called.
68
- * `useMutation` does not care about what the function does, all it needs it a function that returns
69
- * a promise.
70
- * @param options Options to configure the mutation.
71
- * @returns An object with the following properties:
72
- * - `mutateAsync`: A function that takes in the variables and returns a promise that resolves to the
73
- * result of the mutation. This function can be awaited to get the result of the mutation. Callbacks can
74
- * be passed to this function to be called when the mutation is successful or when it fails. It's good idea
75
- * to wrap this function in a try/catch block.
76
- * - `mutate`: A function that takes in the variables and returns nothing. This function does not
77
- * return a promise. Callbacks can be passed to this function to be called when the mutation is
78
- * successful or when it fails.
79
- * - `status`: The status of the mutation. Can be one of `idle`, `loading`, `success` or `error`.
80
- * - `result`: The result of the mutation. This is undefined until the mutation is successful.
81
- * - `reset`: A function that resets the mutation to the initial state.
82
- * - `error`: The error object if the mutation has failed.
83
- * @example
84
- * ```typescript
85
- * const mutationRes = useMutation({
86
- * mutationFn: (variables) => {
87
- * return ZMQHelper.callSomethingAsync(variables)
88
- * },
89
- * onSuccess: (data) => {
90
- * // do something with the result
91
- * },
92
- * onError: (error) => {
93
- * // do something with the error
94
- * },
95
- * onSettled: (data, error) => {
96
- * // do something when the mutation is done
97
- * }});
98
- *
99
- * // call the mutation
100
- * const res = await mutationRes.mutateAsync({ foo: "bar" });
101
- * // OR
102
- * mutationRes.mutate({ foo: "bar" }, {
103
- * onSuccess: (data) => {
104
- * // do something with the result
105
- * // for example show a toast message
106
- * // stop local loading state
107
- * });
108
- * ```
109
- */
110
82
  export const useMutation = <
111
83
  TData = unknown,
112
84
  TError = TMutationError<unknown>,
113
85
  TParams = void,
86
+ TMetadata = unknown,
114
87
  >(
115
- options: MutationOptions<TData, TError, TParams>
88
+ options: MutationOptions<TData, TError, TParams, TMetadata>
116
89
  ) => {
117
90
  const {
118
91
  mutationFn,
@@ -142,79 +115,77 @@ export const useMutation = <
142
115
  const internalCallbackRef = useRef(internalCallbackRefistry);
143
116
  internalCallbackRef.current = internalCallbackRefistry;
144
117
 
145
- const mutateAsync = useCallback(
146
- async (params: TParams, overrideTargetMachine?: string) => {
147
- setStatus("loading");
148
- setError(null);
149
-
150
- try {
151
- const promises: RacePromises<TData>[] = [
152
- mutationFnRef.current(
153
- internalCallbackRef.current.prepareParams
154
- ? internalCallbackRef.current.prepareParams(
155
- params,
156
- internalOptionsRef.current.params
118
+ const mutateAsync = useCallback(async (params: TParams, meta?: TMetadata) => {
119
+ setStatus("loading");
120
+ setError(null);
121
+
122
+ try {
123
+ const promises: RacePromises<TData>[] = [
124
+ mutationFnRef.current(
125
+ internalCallbackRef.current.prepareParams
126
+ ? internalCallbackRef.current.prepareParams(
127
+ params,
128
+ internalOptionsRef.current.params,
129
+ meta
130
+ )
131
+ : params,
132
+ meta
133
+ ),
134
+ ...(internalOptionsRef.current.timeout
135
+ ? [
136
+ new Promise<RaceErrorReason>((resolve) =>
137
+ setTimeout(
138
+ () => resolve("timeout"),
139
+ internalOptionsRef.current.timeout
157
140
  )
158
- : params,
159
- overrideTargetMachine
160
- ),
161
- ...(internalOptionsRef.current.timeout
162
- ? [
163
- new Promise<RaceErrorReason>((resolve) =>
164
- setTimeout(
165
- () => resolve("timeout"),
166
- internalOptionsRef.current.timeout
167
- )
168
- ),
169
- ]
170
- : []),
171
- ];
172
-
173
- const res = await Promise.race(promises);
174
-
175
- if (res === "timeout") {
176
- throw new Error("timeout");
177
- }
141
+ ),
142
+ ]
143
+ : []),
144
+ ];
178
145
 
179
- if (internalCallbackRef.current.compareOrThrow?.(res)) {
180
- throw new ComparisonFailError(JSON.stringify(res), res);
181
- }
146
+ const res = await Promise.race(promises);
182
147
 
183
- setResult(res);
184
- setStatus("success");
148
+ if (res === "timeout") {
149
+ throw new Error("timeout");
150
+ }
185
151
 
186
- internalCallbackRef.current.onSuccess?.(res, params);
187
- internalCallbackRef.current.onSettled?.(res, null, params);
152
+ if (internalCallbackRef.current.compareOrThrow?.(res)) {
153
+ throw new ComparisonFailError(JSON.stringify(res), res);
154
+ }
188
155
 
189
- return res;
190
- } catch (error: any) {
191
- setError(error);
192
- setStatus("error");
156
+ setResult(res);
157
+ setStatus("success");
193
158
 
194
- internalCallbackRef.current.onError?.(error, params);
195
- internalCallbackRef.current.onSettled?.(undefined, error, params);
159
+ internalCallbackRef.current.onSuccess?.(res, params, meta);
160
+ internalCallbackRef.current.onSettled?.(res, null, params, meta);
196
161
 
197
- throw error;
198
- }
199
- },
200
- []
201
- );
162
+ return res;
163
+ } catch (error: any) {
164
+ setError(error);
165
+ setStatus("error");
166
+
167
+ internalCallbackRef.current.onError?.(error, params, meta);
168
+ internalCallbackRef.current.onSettled?.(undefined, error, params, meta);
169
+
170
+ throw error;
171
+ }
172
+ }, []);
202
173
 
203
174
  const mutate = useCallback(
204
175
  (
205
176
  variables: TParams,
206
- options?: MutateOptions<TData, TError, TParams> & {
207
- overrideTargetMachine?: string;
177
+ options?: MutateOptions<TData, TError, TParams, TMetadata> & {
178
+ meta?: TMetadata;
208
179
  }
209
180
  ) => {
210
- mutateAsync(variables, options?.overrideTargetMachine).then(
181
+ mutateAsync(variables, options?.meta).then(
211
182
  (data) => {
212
- options?.onSuccess?.(data, variables);
213
- options?.onSettled?.(data, null, variables);
183
+ options?.onSuccess?.(data, variables, options?.meta);
184
+ options?.onSettled?.(data, null, variables, options?.meta);
214
185
  },
215
186
  (error) => {
216
- options?.onError?.(error, variables);
217
- options?.onSettled?.(undefined, error, variables);
187
+ options?.onError?.(error, variables, options?.meta);
188
+ options?.onSettled?.(undefined, error, variables, options?.meta);
218
189
  }
219
190
  );
220
191
  },
@@ -1,210 +1,162 @@
1
1
  import { fireEvent } from "@testing-library/dom";
2
2
  import { act, renderHook, waitFor } from "@testing-library/react";
3
- import { vi, describe, beforeEach, it, expect, test } from "vitest";
3
+ import { vi, describe, it, expect, test } from "vitest";
4
4
 
5
5
  import { useQuery } from "./useQuery";
6
- import { MockUseQueryUtils } from "./mock/useQuery";
7
6
  const mockQueryKey = ["dummyQK"];
8
7
 
9
- function until(condition: boolean) {
10
- return new Promise((resolve, reject) => {
11
- if (condition) {
12
- resolve(null);
13
- } else {
14
- reject();
15
- }
16
- });
17
- }
18
-
19
8
  describe("useQuery", () => {
20
- let defaultQueryMock: MockUseQueryUtils;
21
-
22
- beforeEach(() => {
23
- defaultQueryMock = new MockUseQueryUtils({});
24
- });
25
-
26
- it("should call queryFn by on mount by default", () => {
27
- const mockFunction = vi.fn(() => defaultQueryMock.getMockedQueryFn());
28
- renderHook(() =>
29
- useQuery({
30
- queryFn: mockFunction,
31
- key: mockQueryKey,
32
- })
9
+ it("should call queryFn by on mount by default", async () => {
10
+ const mockFunction = vi.fn();
11
+ await act(() =>
12
+ renderHook(() =>
13
+ useQuery({
14
+ queryFn: mockFunction,
15
+ key: mockQueryKey,
16
+ })
17
+ )
33
18
  );
34
-
35
19
  expect(mockFunction).toBeCalledTimes(1);
36
20
  });
37
- it("should be in loading state on mount", () => {
21
+ it("should be in loading state on mount", async () => {
38
22
  const { result } = renderHook(() =>
39
23
  useQuery({
40
- queryFn: () => defaultQueryMock.getMockedQueryFn(),
24
+ queryFn: vi.fn(),
41
25
  key: mockQueryKey,
42
26
  })
43
27
  );
44
28
 
45
- expect(result.current.status).toBe("loading");
29
+ await waitFor(() => expect(result.current.status).toBe("loading"));
46
30
  });
47
31
  it("should be in success state after queryFn resolves", async () => {
32
+ const mockFunction = vi.fn();
48
33
  const { result } = renderHook(() =>
49
34
  useQuery({
50
- queryFn: () => defaultQueryMock.getMockedQueryFn(),
35
+ queryFn: mockFunction,
51
36
  key: mockQueryKey,
52
37
  })
53
38
  );
54
39
  act(() => {
55
- defaultQueryMock.resolve();
56
- });
57
- await waitFor(() => until(result.current.status === "success"), {
58
- timeout: 1000,
40
+ mockFunction.mockResolvedValue("test");
59
41
  });
42
+ await waitFor(() => expect(result.current.status).toBe("success"));
60
43
  });
61
44
  it("should be in error state after queryFn rejects", async () => {
45
+ const mockFunction = vi.fn().mockRejectedValue("test");
62
46
  const { result } = renderHook(() =>
63
47
  useQuery({
64
- queryFn: () => defaultQueryMock.getMockedQueryFn(),
48
+ queryFn: mockFunction,
65
49
  key: mockQueryKey,
66
50
  })
67
51
  );
68
- act(() => defaultQueryMock.reject());
69
- await waitFor(() => until(result.current.status === "error"), {
70
- timeout: 1000,
71
- });
72
- expect(result.current.status).toBe("error");
52
+ await waitFor(() => expect(result.current.status).toBe("error"));
73
53
  });
74
54
  it("should be in timeout state after queryFn rejects with timeout", async () => {
55
+ const mockFunction = vi.fn(
56
+ () => new Promise((_, reject) => setTimeout(() => reject("test"), 10))
57
+ );
75
58
  const { result } = renderHook(() =>
76
59
  useQuery({
77
- queryFn: () => defaultQueryMock.getMockedQueryFn(),
60
+ queryFn: mockFunction,
78
61
  key: mockQueryKey,
79
62
  timeout: 0.01,
80
63
  })
81
64
  );
82
- await waitFor(() => until(result.current.status === "error"), {
83
- timeout: 1000,
84
- });
85
- expect(result.current.status === "error");
65
+ await waitFor(() => expect(result.current.status).toBe("error"));
86
66
  });
87
67
  it("should be in success state after queryFn resolves with initialData", async () => {
88
68
  const { result } = renderHook(() =>
89
69
  useQuery({
90
- queryFn: () => defaultQueryMock.getMockedQueryFn(),
70
+ queryFn: vi.fn().mockResolvedValue("test-test-2"),
91
71
  key: mockQueryKey,
92
72
  initialData: "test-test",
93
73
  })
94
74
  );
95
- defaultQueryMock.resolve();
96
- await waitFor(() => until(result.current.status === "success"), {
97
- timeout: 1000,
98
- });
75
+ await waitFor(() => expect(result.current.status).toBe("success"));
99
76
  });
100
77
  it("should be in idle state if enabled is false", async () => {
101
78
  const { result } = renderHook(() =>
102
79
  useQuery({
103
- queryFn: () => defaultQueryMock.getMockedQueryFn(),
80
+ queryFn: vi.fn(),
104
81
  key: mockQueryKey,
105
82
  enabled: false,
106
83
  })
107
84
  );
108
- expect(result.current.status).toBe("idle");
85
+ await waitFor(() => expect(result.current.status).toBe("idle"));
109
86
  });
110
87
  test("refetch should trigger query function", async () => {
111
- const resolver = vi.fn(() => defaultQueryMock.getMockedQueryFn());
112
- const { result } = await act(() =>
113
- renderHook(() =>
114
- useQuery({
115
- queryFn: resolver,
116
- key: mockQueryKey,
117
- })
118
- )
88
+ const resolver = vi.fn().mockResolvedValue("test");
89
+ const { result } = renderHook(() =>
90
+ useQuery({
91
+ queryFn: resolver,
92
+ key: mockQueryKey,
93
+ })
119
94
  );
120
- await act(() => defaultQueryMock.resolve());
121
- await waitFor(() => until(result.current.status === "success"), {
122
- timeout: 1000,
123
- });
124
- await act(() => result.current.refetch());
95
+ await waitFor(() => expect(result.current.status).toBe("success"));
96
+ await act(() => result.current.refetch({}));
125
97
  expect(resolver).toBeCalledTimes(2);
126
98
  });
127
- test("select should return selected right data", async () => {
128
- const queryMock = new MockUseQueryUtils({
129
- foo: "bar",
130
- baz: "qux",
131
- });
99
+ test("select should return correctly selected data", async () => {
100
+ const resolver = vi.fn().mockResolvedValue({ foo: "bar" });
132
101
  const { result } = renderHook(() =>
133
102
  useQuery({
134
- queryFn: () => queryMock.getMockedQueryFn(),
103
+ queryFn: resolver,
135
104
  key: mockQueryKey,
136
- select: (data) => data?.foo,
105
+ select: (data: any) => data?.foo,
137
106
  })
138
107
  );
139
- expect(result.current.data).toBeUndefined();
140
- queryMock.resolve();
141
- await waitFor(() => until(result.current.data !== undefined), {
142
- timeout: 1000,
143
- });
144
- expect(result.current.data).toBe("bar");
108
+ await waitFor(() => expect(result.current.data).toBe("bar"));
145
109
  });
146
110
  test("onSuccess should be called after queryFn resolves", async () => {
147
111
  const onSuccess = vi.fn();
148
112
  renderHook(() =>
149
113
  useQuery({
150
- queryFn: () => defaultQueryMock.getMockedQueryFn(),
114
+ queryFn: vi.fn().mockResolvedValue("test"),
151
115
  key: mockQueryKey,
152
116
  onSuccess,
153
117
  })
154
118
  );
155
- await act(() => defaultQueryMock.resolve());
156
- await waitFor(() => {}, {
157
- timeout: 1000,
158
- });
159
- expect(onSuccess).toBeCalledTimes(1);
119
+ await waitFor(() => expect(onSuccess).toBeCalledTimes(1));
120
+ expect(onSuccess).toBeCalledWith("test");
160
121
  });
161
122
  test("onError should be called after queryFn rejects", async () => {
162
123
  const onError = vi.fn();
163
124
  renderHook(() =>
164
125
  useQuery({
165
- queryFn: () => defaultQueryMock.getMockedQueryFn(),
126
+ queryFn: vi.fn().mockRejectedValue("test"),
166
127
  key: mockQueryKey,
167
128
  onError,
168
129
  })
169
130
  );
170
- await act(() => defaultQueryMock.reject());
171
- await waitFor(() => {}, {
172
- timeout: 1000,
173
- });
174
- expect(onError).toBeCalledTimes(1);
131
+ await waitFor(() => expect(onError).toBeCalledTimes(1));
132
+ expect(onError).toBeCalledWith("test");
175
133
  });
176
134
  test("onSettled should be called after queryFn resolves", async () => {
177
135
  const onSettled = vi.fn();
178
136
  renderHook(() =>
179
137
  useQuery({
180
- queryFn: () => defaultQueryMock.getMockedQueryFn(),
138
+ queryFn: vi.fn().mockResolvedValue("test"),
181
139
  key: mockQueryKey,
182
140
  onSettled,
183
141
  })
184
142
  );
185
- await act(() => defaultQueryMock.resolve());
186
- await waitFor(() => {}, {
187
- timeout: 1000,
188
- });
189
- expect(onSettled).toBeCalledTimes(1);
143
+ await waitFor(() => expect(onSettled).toBeCalledTimes(1));
144
+ expect(onSettled).toBeCalledWith("test", undefined);
190
145
  });
191
146
  test("onSettled should be called after queryFn rejects", async () => {
192
147
  const onSettled = vi.fn();
193
148
  renderHook(() =>
194
149
  useQuery({
195
- queryFn: () => defaultQueryMock.getMockedQueryFn(),
150
+ queryFn: vi.fn().mockRejectedValue("test"),
196
151
  key: mockQueryKey,
197
152
  onSettled,
198
153
  })
199
154
  );
200
- await act(() => defaultQueryMock.reject());
201
- await waitFor(() => {}, {
202
- timeout: 1000,
203
- });
204
- expect(onSettled).toBeCalledTimes(1);
155
+ await waitFor(() => expect(onSettled).toBeCalledTimes(1));
156
+ expect(onSettled).toBeCalledWith(undefined, "test");
205
157
  });
206
158
  test("refetch is triggered on window focus", async () => {
207
- const resolver = vi.fn(() => defaultQueryMock.getMockedQueryFn());
159
+ const resolver = vi.fn().mockResolvedValue("test");
208
160
  const { result } = await act(() =>
209
161
  renderHook(() =>
210
162
  useQuery({
@@ -214,15 +166,12 @@ describe("useQuery", () => {
214
166
  })
215
167
  )
216
168
  );
217
- await act(() => defaultQueryMock.resolve());
218
- await waitFor(() => until(result.current.status === "success"), {
219
- timeout: 1000,
220
- });
169
+ await waitFor(() => expect(result.current.status).toBe("success"));
221
170
  await act(() => fireEvent(window, new FocusEvent("focus")));
222
171
  expect(resolver).toBeCalledTimes(2);
223
172
  });
224
173
  test("refetch interval should work", async () => {
225
- const resolver = vi.fn(() => defaultQueryMock.getMockedQueryFn());
174
+ const resolver = vi.fn().mockResolvedValue("test");
226
175
  const { result } = renderHook(() =>
227
176
  useQuery({
228
177
  queryFn: resolver,
@@ -230,38 +179,31 @@ describe("useQuery", () => {
230
179
  key: mockQueryKey,
231
180
  })
232
181
  );
233
- await act(() => defaultQueryMock.resolve());
234
- await waitFor(() => until(result.current.status === "success"), {
235
- timeout: 1000,
236
- });
237
- waitFor(() => until(resolver.call.length > 1), { timeout: 1000 });
182
+ await waitFor(() => expect(result.current.status).toBe("success"));
183
+ await waitFor(() => expect(resolver.mock.calls.length).toBeGreaterThan(1));
238
184
  });
239
185
  test("refetch should automatically trigger if queryKey is changed", async () => {
240
- const resolver = vi.fn(() => defaultQueryMock.getMockedQueryFn());
241
- const { result, rerender } = await act(() =>
242
- renderHook(
243
- (props) =>
244
- useQuery({
245
- queryFn: resolver,
246
- key: props.key,
247
- }),
248
- {
249
- initialProps: {
250
- key: ["dummyQK1"],
251
- },
252
- }
253
- )
254
- );
255
- await act(() => defaultQueryMock.resolve());
256
- await waitFor(() => until(result.current.status === "success"), {
257
- timeout: 1000,
258
- });
186
+ const resolver = vi.fn().mockResolvedValue("test");
187
+ const { result, rerender } = renderHook(
188
+ (props) =>
189
+ useQuery({
190
+ queryFn: resolver,
191
+ key: props.key,
192
+ }),
193
+ {
194
+ initialProps: {
195
+ key: ["dummyQK1"],
196
+ },
197
+ }
198
+ );
199
+ await waitFor(() => expect(result.current.status).toBe("success"));
200
+ await waitFor(() => expect(resolver).toBeCalledTimes(1));
259
201
  rerender({ key: ["dummyQK2"] });
260
202
  rerender({ key: ["dummyQK3"] });
261
- expect(resolver).toBeCalledTimes(3);
203
+ await waitFor(() => expect(resolver).toBeCalledTimes(3));
262
204
  });
263
205
  test("stateless mode", async () => {
264
- const resolver = vi.fn(() => defaultQueryMock.getMockedQueryFn());
206
+ const resolver = vi.fn().mockResolvedValue("test");
265
207
  const { result } = renderHook(() =>
266
208
  useQuery({
267
209
  queryFn: resolver,
@@ -269,11 +211,7 @@ describe("useQuery", () => {
269
211
  stateless: true,
270
212
  })
271
213
  );
272
- await act(() => defaultQueryMock.resolve());
273
- await waitFor(() => until(result.current.status === "success"), {
274
- timeout: 1000,
275
- });
276
-
214
+ await waitFor(() => expect(result.current.status).toBe("success"));
277
215
  // Here ts should kick in and complain about but for testing purposes, all good
278
216
  // @ts-ignore
279
217
  expect(result.current.data).toBeUndefined();
package/src/useQuery.ts CHANGED
@@ -259,14 +259,11 @@ export const useQuery = <
259
259
 
260
260
  // If the query should be refetched on an interval, add an interval
261
261
  if (refetchInterval > 0) {
262
- const interval = setInterval(
263
- () => {
264
- if (shouldRefetch()) {
265
- refetch();
266
- }
267
- },
268
- Math.max(refetchInterval, 1000)
269
- );
262
+ const interval = setInterval(() => {
263
+ if (shouldRefetch()) {
264
+ refetch();
265
+ }
266
+ }, refetchInterval);
270
267
 
271
268
  cleanups.push(() => {
272
269
  clearInterval(interval);