@trackunit/react-graphql-hooks 1.10.9 → 1.10.12
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.
- package/index.cjs.js +175 -116
- package/index.esm.js +178 -119
- package/package.json +4 -4
- package/src/paginationQueryUtils.d.ts +53 -0
- package/src/usePaginationQuery.d.ts +8 -10
package/index.cjs.js
CHANGED
|
@@ -127,6 +127,121 @@ const useLazyQuery = (document, options) => {
|
|
|
127
127
|
return react.useMemo(() => [executeQuery, enhancedResult], [executeQuery, enhancedResult]);
|
|
128
128
|
};
|
|
129
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Converts pagination variables from cursor-based (first/after) to page-based (page/pageSize) if needed.
|
|
132
|
+
* Returns the appropriate variables based on the pagination type.
|
|
133
|
+
*/
|
|
134
|
+
const convertPaginationVariables = (baseVariables, paginationVars) => {
|
|
135
|
+
const usesPageBasedPagination = baseVariables !== undefined && "page" in baseVariables && "pageSize" in baseVariables;
|
|
136
|
+
const paginationVariables = usesPageBasedPagination
|
|
137
|
+
? {
|
|
138
|
+
pageSize: paginationVars.first,
|
|
139
|
+
page: Number(paginationVars.after ?? 0),
|
|
140
|
+
}
|
|
141
|
+
: { ...paginationVars };
|
|
142
|
+
return {
|
|
143
|
+
...baseVariables,
|
|
144
|
+
...paginationVariables,
|
|
145
|
+
};
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* Creates an update query handler for Apollo's fetchMore.
|
|
149
|
+
* Handles aborted requests and merges new data with existing data.
|
|
150
|
+
*/
|
|
151
|
+
const createUpdateQueryHandler = (params) => {
|
|
152
|
+
return (_previousResult, { fetchMoreResult }) => {
|
|
153
|
+
// Handle aborted requests by returning previous data
|
|
154
|
+
if (params.abortSignal.aborted) {
|
|
155
|
+
// If prev does not hold any data we don't want to return it,
|
|
156
|
+
// since it will make the cache output an error to the console.
|
|
157
|
+
// https://github.com/apollographql/apollo-client/issues/8677
|
|
158
|
+
if (params.prev !== undefined && params.prev !== null) {
|
|
159
|
+
// Type assertion required: Apollo's updateQuery expects its own result type
|
|
160
|
+
return sharedUtils.objectKeys(params.prev).length === 0
|
|
161
|
+
? undefined
|
|
162
|
+
: params.prev;
|
|
163
|
+
}
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
// Type assertion required: Apollo's fetchMoreResult has complex internal types
|
|
167
|
+
// that need to be cast to our TData generic for type-safe usage
|
|
168
|
+
const typedResult = fetchMoreResult;
|
|
169
|
+
params.onLastFetchedUpdate(typedResult);
|
|
170
|
+
const result = params.onUpdate(params.prev, typedResult);
|
|
171
|
+
params.onPageInfoUpdate(result.pageInfo ?? null);
|
|
172
|
+
params.onDataUpdate(result.data);
|
|
173
|
+
params.onLoadingComplete();
|
|
174
|
+
return result.data;
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* Creates a reducer function for managing pagination state.
|
|
179
|
+
* Handles data updates, reset, and reset trigger increments.
|
|
180
|
+
*/
|
|
181
|
+
const createPaginationReducer = () => {
|
|
182
|
+
return (state, action) => {
|
|
183
|
+
switch (action.type) {
|
|
184
|
+
case "SET_DATA": {
|
|
185
|
+
return { ...state, data: action.payload };
|
|
186
|
+
}
|
|
187
|
+
case "SET_LAST_FETCHED_DATA": {
|
|
188
|
+
return { ...state, lastFetchedData: action.payload };
|
|
189
|
+
}
|
|
190
|
+
case "RESET": {
|
|
191
|
+
return { ...state, data: undefined, lastFetchedData: undefined };
|
|
192
|
+
}
|
|
193
|
+
case "INCREMENT_RESET_TRIGGER": {
|
|
194
|
+
return { ...state, resetTrigger: state.resetTrigger + 1 };
|
|
195
|
+
}
|
|
196
|
+
default: {
|
|
197
|
+
throw new Error(`${action} is not a known action type`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Hook to stabilize variables based on deep equality comparison.
|
|
205
|
+
* Prevents unnecessary re-fetches when parent components pass new variable objects
|
|
206
|
+
* with the same content.
|
|
207
|
+
*/
|
|
208
|
+
const useStableVariables = (variables) => {
|
|
209
|
+
const [stableVariables, setStableVariables] = react.useState(variables);
|
|
210
|
+
reactComponents.useWatch({
|
|
211
|
+
value: variables,
|
|
212
|
+
onChange: setStableVariables,
|
|
213
|
+
skip: !Boolean(variables),
|
|
214
|
+
});
|
|
215
|
+
return stableVariables;
|
|
216
|
+
};
|
|
217
|
+
/**
|
|
218
|
+
* Hook to manage AbortController for cancellable requests.
|
|
219
|
+
* Returns an abort signal that can be passed to fetch requests and a function to create new controllers.
|
|
220
|
+
*/
|
|
221
|
+
const useAbortableRequest = () => {
|
|
222
|
+
const [abortController] = react.useState(() => new AbortController());
|
|
223
|
+
const firstRender = reactComponents.useIsFirstRender();
|
|
224
|
+
react.useEffect(() => {
|
|
225
|
+
if (firstRender) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
return () => {
|
|
229
|
+
abortController.abort();
|
|
230
|
+
};
|
|
231
|
+
}, [abortController, firstRender]);
|
|
232
|
+
return { abortSignal: abortController.signal };
|
|
233
|
+
};
|
|
234
|
+
/**
|
|
235
|
+
* Hook to sync a value to a ref and return the ref.
|
|
236
|
+
* Useful for avoiding dependency cycles in effects.
|
|
237
|
+
*/
|
|
238
|
+
const useSyncedRef = (value) => {
|
|
239
|
+
const ref = react.useRef(value);
|
|
240
|
+
react.useEffect(() => {
|
|
241
|
+
ref.current = value;
|
|
242
|
+
}, [value]);
|
|
243
|
+
return ref;
|
|
244
|
+
};
|
|
130
245
|
/**
|
|
131
246
|
* This hook is used to fetch data from a GraphQL query and support pagination, it will help maintain the data and the pagination.
|
|
132
247
|
*
|
|
@@ -137,17 +252,15 @@ const useLazyQuery = (document, options) => {
|
|
|
137
252
|
* lastFetchedData is used to store the last fetched data, so you can update data according to last page.
|
|
138
253
|
*
|
|
139
254
|
* @example
|
|
140
|
-
*
|
|
141
255
|
* const {
|
|
142
256
|
* data,
|
|
143
257
|
* loading,
|
|
144
258
|
* pagination,
|
|
145
259
|
* lastFetchedData,
|
|
146
|
-
*} = usePaginationQuery({
|
|
147
|
-
* query: myLazyQuery, // <-- myLazyQuery is the graphql LazyQuery to run pagination for.
|
|
260
|
+
* } = usePaginationQuery(MyAssetsDocument, {
|
|
148
261
|
* updateQuery: (previous, newData) => {
|
|
149
|
-
*
|
|
150
|
-
*
|
|
262
|
+
* // Here you can use the unionEdgesByNodeKey utils to merge your edges together.
|
|
263
|
+
* if (newData?.assets?.edges) {
|
|
151
264
|
* return {
|
|
152
265
|
* data: {
|
|
153
266
|
* ...newData,
|
|
@@ -162,40 +275,23 @@ const useLazyQuery = (document, options) => {
|
|
|
162
275
|
* return { data: newData, pageInfo: newData.assets.pageInfo };
|
|
163
276
|
* },
|
|
164
277
|
* });
|
|
165
|
-
* @template TData
|
|
166
|
-
* @template TVariables
|
|
167
|
-
* @param
|
|
168
|
-
* @param
|
|
169
|
-
* @returns {
|
|
278
|
+
* @template TData - The type of the query result data.
|
|
279
|
+
* @template TVariables - The type of the query variables.
|
|
280
|
+
* @param document - The GraphQL query document.
|
|
281
|
+
* @param props - The properties for configuring the query. This includes the `updateQuery` function for merging new and existing data, and options for pagination such as `pageSize`. Also includes other lazy query hook options from Apollo Client.
|
|
282
|
+
* @returns {PaginationQuery<TData>} The pagination query result containing data, loading state, pagination controls, and lastFetchedData.
|
|
170
283
|
*/
|
|
171
284
|
const usePaginationQuery = (document, props) => {
|
|
172
|
-
|
|
173
|
-
const [
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
//
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const variablesRef = react.useRef(props.variables);
|
|
183
|
-
// Use effect to update the ref when props.variables changes
|
|
184
|
-
react.useEffect(() => {
|
|
185
|
-
if (!esToolkit.isEqual(props.variables, variablesRef.current)) {
|
|
186
|
-
variablesRef.current = props.variables;
|
|
187
|
-
setStableVariables(props.variables);
|
|
188
|
-
if (!props.skip) {
|
|
189
|
-
if (lastAbortController) {
|
|
190
|
-
lastAbortController.abort();
|
|
191
|
-
}
|
|
192
|
-
const newAbortController = new AbortController();
|
|
193
|
-
setLastAbortController(newAbortController);
|
|
194
|
-
setAbortController(newAbortController);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
// eslint-disable-next-line
|
|
198
|
-
}, [props.variables]);
|
|
285
|
+
// Use reducer to manage interconnected pagination state
|
|
286
|
+
const [state, dispatch] = react.useReducer(createPaginationReducer(), {
|
|
287
|
+
data: undefined,
|
|
288
|
+
lastFetchedData: undefined,
|
|
289
|
+
resetTrigger: 0,
|
|
290
|
+
});
|
|
291
|
+
// Stabilize variables to prevent unnecessary re-fetches
|
|
292
|
+
const stableVariables = useStableVariables(props.variables);
|
|
293
|
+
// Manage abort controller for cancellable requests
|
|
294
|
+
const { abortSignal } = useAbortableRequest();
|
|
199
295
|
const internalProps = react.useMemo(() => {
|
|
200
296
|
return {
|
|
201
297
|
...props,
|
|
@@ -208,7 +304,7 @@ const usePaginationQuery = (document, props) => {
|
|
|
208
304
|
...internalProps.context,
|
|
209
305
|
fetchOptions: {
|
|
210
306
|
...internalProps.context?.fetchOptions,
|
|
211
|
-
signal:
|
|
307
|
+
signal: abortSignal,
|
|
212
308
|
},
|
|
213
309
|
},
|
|
214
310
|
pollInterval: internalProps.pollInterval,
|
|
@@ -216,7 +312,7 @@ const usePaginationQuery = (document, props) => {
|
|
|
216
312
|
onCompleted: completedData => {
|
|
217
313
|
if (networkStatus === client.NetworkStatus.refetch) {
|
|
218
314
|
// trigger reset for refetchQueries for the provided document.
|
|
219
|
-
|
|
315
|
+
dispatch({ type: "INCREMENT_RESET_TRIGGER" });
|
|
220
316
|
}
|
|
221
317
|
if (internalProps.onCompleted) {
|
|
222
318
|
internalProps.onCompleted(completedData);
|
|
@@ -228,15 +324,14 @@ const usePaginationQuery = (document, props) => {
|
|
|
228
324
|
nextFetchPolicy: "network-only",
|
|
229
325
|
initialFetchPolicy: "network-only",
|
|
230
326
|
});
|
|
231
|
-
const [data, setData] = react.useState();
|
|
232
327
|
const onReset = react.useCallback(() => {
|
|
233
|
-
|
|
328
|
+
dispatch({ type: "INCREMENT_RESET_TRIGGER" });
|
|
234
329
|
}, []);
|
|
235
330
|
react.useEffect(() => {
|
|
236
331
|
onReset();
|
|
237
332
|
}, [document, onReset]);
|
|
238
333
|
const { table: { setIsLoading, isLoading, setPageInfo, pageInfo, reset, nextPage, previousPage }, variables: { first, after, last, before }, } = reactComponents.useRelayPagination({
|
|
239
|
-
pageSize: internalProps.pageSize
|
|
334
|
+
pageSize: internalProps.pageSize ?? internalProps.variables?.first ?? reactComponents.defaultPageSize,
|
|
240
335
|
onReset,
|
|
241
336
|
});
|
|
242
337
|
const doFetchMore = react.useCallback((variables, prev) => {
|
|
@@ -245,47 +340,25 @@ const usePaginationQuery = (document, props) => {
|
|
|
245
340
|
return;
|
|
246
341
|
}
|
|
247
342
|
setIsLoading(true);
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
*/
|
|
251
|
-
const fetchMoreVariables = {
|
|
252
|
-
...internalProps.variables,
|
|
253
|
-
...(internalProps.variables && "page" in internalProps.variables && "pageSize" in internalProps.variables
|
|
254
|
-
? {
|
|
255
|
-
pageSize: variables.first,
|
|
256
|
-
page: Number(variables.after) || 0,
|
|
257
|
-
}
|
|
258
|
-
: { ...variables }),
|
|
259
|
-
};
|
|
343
|
+
// Convert pagination variables based on pagination type (cursor vs page-based)
|
|
344
|
+
const fetchMoreVariables = convertPaginationVariables(internalProps.variables, variables);
|
|
260
345
|
fetchMore({
|
|
261
346
|
variables: fetchMoreVariables,
|
|
262
|
-
updateQuery: (
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
}
|
|
272
|
-
return undefined;
|
|
273
|
-
}
|
|
274
|
-
// Safely handle Apollo types
|
|
275
|
-
const typedResult = fetchMoreResult;
|
|
276
|
-
setLastFetchedData(typedResult);
|
|
277
|
-
const result = internalProps.updateQuery(prev, typedResult);
|
|
278
|
-
setPageInfo(result.pageInfo || null);
|
|
279
|
-
setData(result.data);
|
|
280
|
-
setIsLoading(false);
|
|
281
|
-
return result.data;
|
|
282
|
-
},
|
|
347
|
+
updateQuery: createUpdateQueryHandler({
|
|
348
|
+
abortSignal,
|
|
349
|
+
prev,
|
|
350
|
+
onUpdate: internalProps.updateQuery,
|
|
351
|
+
onDataUpdate: (data) => dispatch({ type: "SET_DATA", payload: data }),
|
|
352
|
+
onLastFetchedUpdate: (data) => dispatch({ type: "SET_LAST_FETCHED_DATA", payload: data }),
|
|
353
|
+
onPageInfoUpdate: setPageInfo,
|
|
354
|
+
onLoadingComplete: () => setIsLoading(false),
|
|
355
|
+
}),
|
|
283
356
|
// It is apparently not possible to use the onError from the useLazyQuery hook so we have to handle it here.
|
|
284
357
|
// However, if you need to pass in your own onError function, you can do so in the props of the hook.
|
|
285
358
|
// But we ignore the error if the request was aborted.
|
|
286
359
|
}).catch(error => {
|
|
287
360
|
setIsLoading(false);
|
|
288
|
-
if (
|
|
361
|
+
if (abortSignal.aborted) {
|
|
289
362
|
return;
|
|
290
363
|
}
|
|
291
364
|
if (internalProps.onError) {
|
|
@@ -295,35 +368,18 @@ const usePaginationQuery = (document, props) => {
|
|
|
295
368
|
throw error;
|
|
296
369
|
}
|
|
297
370
|
});
|
|
298
|
-
}, [internalProps, setIsLoading, fetchMore,
|
|
371
|
+
}, [internalProps, setIsLoading, fetchMore, abortSignal, setPageInfo]);
|
|
299
372
|
react.useEffect(() => {
|
|
300
|
-
|
|
373
|
+
dispatch({ type: "RESET" });
|
|
301
374
|
reset();
|
|
302
|
-
}, [
|
|
303
|
-
//
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
beforeRef.current = before;
|
|
311
|
-
}, [before]);
|
|
312
|
-
const firstRef = react.useRef(first);
|
|
313
|
-
react.useEffect(() => {
|
|
314
|
-
firstRef.current = first;
|
|
315
|
-
}, [first]);
|
|
316
|
-
// Use a ref to track the current data
|
|
317
|
-
const dataRef = react.useRef(data);
|
|
318
|
-
react.useEffect(() => {
|
|
319
|
-
dataRef.current = data;
|
|
320
|
-
}, [data]);
|
|
321
|
-
// Store doFetchMore in a ref to avoid dependency cycles
|
|
322
|
-
const doFetchMoreRef = react.useRef(doFetchMore);
|
|
323
|
-
react.useEffect(() => {
|
|
324
|
-
doFetchMoreRef.current = doFetchMore;
|
|
325
|
-
}, [doFetchMore]);
|
|
326
|
-
// Stabilize the fetchMore call by using refs instead of direct dependencies
|
|
375
|
+
}, [stableVariables, reset]);
|
|
376
|
+
// Store pagination values in refs to avoid triggering unnecessary effect re-runs
|
|
377
|
+
const firstRef = useSyncedRef(first);
|
|
378
|
+
const lastRef = useSyncedRef(last);
|
|
379
|
+
const beforeRef = useSyncedRef(before);
|
|
380
|
+
const dataRef = useSyncedRef(state.data);
|
|
381
|
+
const doFetchMoreRef = useSyncedRef(doFetchMore);
|
|
382
|
+
// Fetch initial page when variables or reset trigger changes
|
|
327
383
|
react.useEffect(() => {
|
|
328
384
|
const fetchVariables = {
|
|
329
385
|
first: firstRef.current,
|
|
@@ -331,30 +387,34 @@ const usePaginationQuery = (document, props) => {
|
|
|
331
387
|
before: undefined,
|
|
332
388
|
after: undefined,
|
|
333
389
|
};
|
|
334
|
-
// Use the ref version to avoid dependency cycles
|
|
335
390
|
doFetchMoreRef.current(fetchVariables, undefined);
|
|
336
|
-
//
|
|
337
|
-
}, [
|
|
338
|
-
//
|
|
391
|
+
// Refs are stable and don't need to trigger re-runs, but included to satisfy linter
|
|
392
|
+
}, [stableVariables, state.resetTrigger, firstRef, doFetchMoreRef]);
|
|
393
|
+
// Fetch next/previous page when after cursor changes
|
|
339
394
|
react.useEffect(() => {
|
|
340
|
-
if (after) {
|
|
341
|
-
const fetchVariables = {
|
|
342
|
-
|
|
395
|
+
if (after !== undefined && after !== null) {
|
|
396
|
+
const fetchVariables = {
|
|
397
|
+
first: firstRef.current,
|
|
398
|
+
after,
|
|
399
|
+
last: lastRef.current,
|
|
400
|
+
before: beforeRef.current,
|
|
401
|
+
};
|
|
343
402
|
doFetchMoreRef.current(fetchVariables, dataRef.current);
|
|
344
403
|
}
|
|
345
|
-
//
|
|
346
|
-
}, [after]);
|
|
404
|
+
// Refs are stable and don't need to trigger re-runs, but included to satisfy linter
|
|
405
|
+
}, [after, firstRef, lastRef, beforeRef, dataRef, doFetchMoreRef]);
|
|
347
406
|
return react.useMemo(() => {
|
|
348
407
|
return {
|
|
349
|
-
data: data
|
|
408
|
+
data: state.data ?? previousData,
|
|
350
409
|
previousData,
|
|
351
410
|
loading: isLoading || lazyLoading,
|
|
352
411
|
pagination: { setIsLoading, isLoading, setPageInfo, pageInfo, reset, nextPage, previousPage },
|
|
353
|
-
lastFetchedData,
|
|
412
|
+
lastFetchedData: state.lastFetchedData,
|
|
354
413
|
reset,
|
|
355
414
|
};
|
|
356
415
|
}, [
|
|
357
|
-
data,
|
|
416
|
+
state.data,
|
|
417
|
+
state.lastFetchedData,
|
|
358
418
|
isLoading,
|
|
359
419
|
lazyLoading,
|
|
360
420
|
setIsLoading,
|
|
@@ -363,7 +423,6 @@ const usePaginationQuery = (document, props) => {
|
|
|
363
423
|
reset,
|
|
364
424
|
nextPage,
|
|
365
425
|
previousPage,
|
|
366
|
-
lastFetchedData,
|
|
367
426
|
previousData,
|
|
368
427
|
]);
|
|
369
428
|
};
|
package/index.esm.js
CHANGED
|
@@ -2,9 +2,9 @@ import 'react/jsx-runtime';
|
|
|
2
2
|
import { registerTranslations } from '@trackunit/i18n-library-translation';
|
|
3
3
|
import { truthy, objectKeys } from '@trackunit/shared-utils';
|
|
4
4
|
import { useLazyQuery as useLazyQuery$1, NetworkStatus, useQuery as useQuery$1 } from '@apollo/client';
|
|
5
|
-
import { omit
|
|
6
|
-
import { useMemo,
|
|
7
|
-
import { useRelayPagination, defaultPageSize } from '@trackunit/react-components';
|
|
5
|
+
import { omit } from 'es-toolkit';
|
|
6
|
+
import { useMemo, useReducer, useCallback, useEffect, useState, useRef } from 'react';
|
|
7
|
+
import { useRelayPagination, defaultPageSize, useWatch, useIsFirstRender } from '@trackunit/react-components';
|
|
8
8
|
|
|
9
9
|
var defaultTranslations = {
|
|
10
10
|
|
|
@@ -125,6 +125,121 @@ const useLazyQuery = (document, options) => {
|
|
|
125
125
|
return useMemo(() => [executeQuery, enhancedResult], [executeQuery, enhancedResult]);
|
|
126
126
|
};
|
|
127
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Converts pagination variables from cursor-based (first/after) to page-based (page/pageSize) if needed.
|
|
130
|
+
* Returns the appropriate variables based on the pagination type.
|
|
131
|
+
*/
|
|
132
|
+
const convertPaginationVariables = (baseVariables, paginationVars) => {
|
|
133
|
+
const usesPageBasedPagination = baseVariables !== undefined && "page" in baseVariables && "pageSize" in baseVariables;
|
|
134
|
+
const paginationVariables = usesPageBasedPagination
|
|
135
|
+
? {
|
|
136
|
+
pageSize: paginationVars.first,
|
|
137
|
+
page: Number(paginationVars.after ?? 0),
|
|
138
|
+
}
|
|
139
|
+
: { ...paginationVars };
|
|
140
|
+
return {
|
|
141
|
+
...baseVariables,
|
|
142
|
+
...paginationVariables,
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* Creates an update query handler for Apollo's fetchMore.
|
|
147
|
+
* Handles aborted requests and merges new data with existing data.
|
|
148
|
+
*/
|
|
149
|
+
const createUpdateQueryHandler = (params) => {
|
|
150
|
+
return (_previousResult, { fetchMoreResult }) => {
|
|
151
|
+
// Handle aborted requests by returning previous data
|
|
152
|
+
if (params.abortSignal.aborted) {
|
|
153
|
+
// If prev does not hold any data we don't want to return it,
|
|
154
|
+
// since it will make the cache output an error to the console.
|
|
155
|
+
// https://github.com/apollographql/apollo-client/issues/8677
|
|
156
|
+
if (params.prev !== undefined && params.prev !== null) {
|
|
157
|
+
// Type assertion required: Apollo's updateQuery expects its own result type
|
|
158
|
+
return objectKeys(params.prev).length === 0
|
|
159
|
+
? undefined
|
|
160
|
+
: params.prev;
|
|
161
|
+
}
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
// Type assertion required: Apollo's fetchMoreResult has complex internal types
|
|
165
|
+
// that need to be cast to our TData generic for type-safe usage
|
|
166
|
+
const typedResult = fetchMoreResult;
|
|
167
|
+
params.onLastFetchedUpdate(typedResult);
|
|
168
|
+
const result = params.onUpdate(params.prev, typedResult);
|
|
169
|
+
params.onPageInfoUpdate(result.pageInfo ?? null);
|
|
170
|
+
params.onDataUpdate(result.data);
|
|
171
|
+
params.onLoadingComplete();
|
|
172
|
+
return result.data;
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Creates a reducer function for managing pagination state.
|
|
177
|
+
* Handles data updates, reset, and reset trigger increments.
|
|
178
|
+
*/
|
|
179
|
+
const createPaginationReducer = () => {
|
|
180
|
+
return (state, action) => {
|
|
181
|
+
switch (action.type) {
|
|
182
|
+
case "SET_DATA": {
|
|
183
|
+
return { ...state, data: action.payload };
|
|
184
|
+
}
|
|
185
|
+
case "SET_LAST_FETCHED_DATA": {
|
|
186
|
+
return { ...state, lastFetchedData: action.payload };
|
|
187
|
+
}
|
|
188
|
+
case "RESET": {
|
|
189
|
+
return { ...state, data: undefined, lastFetchedData: undefined };
|
|
190
|
+
}
|
|
191
|
+
case "INCREMENT_RESET_TRIGGER": {
|
|
192
|
+
return { ...state, resetTrigger: state.resetTrigger + 1 };
|
|
193
|
+
}
|
|
194
|
+
default: {
|
|
195
|
+
throw new Error(`${action} is not a known action type`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Hook to stabilize variables based on deep equality comparison.
|
|
203
|
+
* Prevents unnecessary re-fetches when parent components pass new variable objects
|
|
204
|
+
* with the same content.
|
|
205
|
+
*/
|
|
206
|
+
const useStableVariables = (variables) => {
|
|
207
|
+
const [stableVariables, setStableVariables] = useState(variables);
|
|
208
|
+
useWatch({
|
|
209
|
+
value: variables,
|
|
210
|
+
onChange: setStableVariables,
|
|
211
|
+
skip: !Boolean(variables),
|
|
212
|
+
});
|
|
213
|
+
return stableVariables;
|
|
214
|
+
};
|
|
215
|
+
/**
|
|
216
|
+
* Hook to manage AbortController for cancellable requests.
|
|
217
|
+
* Returns an abort signal that can be passed to fetch requests and a function to create new controllers.
|
|
218
|
+
*/
|
|
219
|
+
const useAbortableRequest = () => {
|
|
220
|
+
const [abortController] = useState(() => new AbortController());
|
|
221
|
+
const firstRender = useIsFirstRender();
|
|
222
|
+
useEffect(() => {
|
|
223
|
+
if (firstRender) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
return () => {
|
|
227
|
+
abortController.abort();
|
|
228
|
+
};
|
|
229
|
+
}, [abortController, firstRender]);
|
|
230
|
+
return { abortSignal: abortController.signal };
|
|
231
|
+
};
|
|
232
|
+
/**
|
|
233
|
+
* Hook to sync a value to a ref and return the ref.
|
|
234
|
+
* Useful for avoiding dependency cycles in effects.
|
|
235
|
+
*/
|
|
236
|
+
const useSyncedRef = (value) => {
|
|
237
|
+
const ref = useRef(value);
|
|
238
|
+
useEffect(() => {
|
|
239
|
+
ref.current = value;
|
|
240
|
+
}, [value]);
|
|
241
|
+
return ref;
|
|
242
|
+
};
|
|
128
243
|
/**
|
|
129
244
|
* This hook is used to fetch data from a GraphQL query and support pagination, it will help maintain the data and the pagination.
|
|
130
245
|
*
|
|
@@ -135,17 +250,15 @@ const useLazyQuery = (document, options) => {
|
|
|
135
250
|
* lastFetchedData is used to store the last fetched data, so you can update data according to last page.
|
|
136
251
|
*
|
|
137
252
|
* @example
|
|
138
|
-
*
|
|
139
253
|
* const {
|
|
140
254
|
* data,
|
|
141
255
|
* loading,
|
|
142
256
|
* pagination,
|
|
143
257
|
* lastFetchedData,
|
|
144
|
-
*} = usePaginationQuery({
|
|
145
|
-
* query: myLazyQuery, // <-- myLazyQuery is the graphql LazyQuery to run pagination for.
|
|
258
|
+
* } = usePaginationQuery(MyAssetsDocument, {
|
|
146
259
|
* updateQuery: (previous, newData) => {
|
|
147
|
-
*
|
|
148
|
-
*
|
|
260
|
+
* // Here you can use the unionEdgesByNodeKey utils to merge your edges together.
|
|
261
|
+
* if (newData?.assets?.edges) {
|
|
149
262
|
* return {
|
|
150
263
|
* data: {
|
|
151
264
|
* ...newData,
|
|
@@ -160,40 +273,23 @@ const useLazyQuery = (document, options) => {
|
|
|
160
273
|
* return { data: newData, pageInfo: newData.assets.pageInfo };
|
|
161
274
|
* },
|
|
162
275
|
* });
|
|
163
|
-
* @template TData
|
|
164
|
-
* @template TVariables
|
|
165
|
-
* @param
|
|
166
|
-
* @param
|
|
167
|
-
* @returns {
|
|
276
|
+
* @template TData - The type of the query result data.
|
|
277
|
+
* @template TVariables - The type of the query variables.
|
|
278
|
+
* @param document - The GraphQL query document.
|
|
279
|
+
* @param props - The properties for configuring the query. This includes the `updateQuery` function for merging new and existing data, and options for pagination such as `pageSize`. Also includes other lazy query hook options from Apollo Client.
|
|
280
|
+
* @returns {PaginationQuery<TData>} The pagination query result containing data, loading state, pagination controls, and lastFetchedData.
|
|
168
281
|
*/
|
|
169
282
|
const usePaginationQuery = (document, props) => {
|
|
170
|
-
|
|
171
|
-
const [
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
//
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const variablesRef = useRef(props.variables);
|
|
181
|
-
// Use effect to update the ref when props.variables changes
|
|
182
|
-
useEffect(() => {
|
|
183
|
-
if (!isEqual(props.variables, variablesRef.current)) {
|
|
184
|
-
variablesRef.current = props.variables;
|
|
185
|
-
setStableVariables(props.variables);
|
|
186
|
-
if (!props.skip) {
|
|
187
|
-
if (lastAbortController) {
|
|
188
|
-
lastAbortController.abort();
|
|
189
|
-
}
|
|
190
|
-
const newAbortController = new AbortController();
|
|
191
|
-
setLastAbortController(newAbortController);
|
|
192
|
-
setAbortController(newAbortController);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
// eslint-disable-next-line
|
|
196
|
-
}, [props.variables]);
|
|
283
|
+
// Use reducer to manage interconnected pagination state
|
|
284
|
+
const [state, dispatch] = useReducer(createPaginationReducer(), {
|
|
285
|
+
data: undefined,
|
|
286
|
+
lastFetchedData: undefined,
|
|
287
|
+
resetTrigger: 0,
|
|
288
|
+
});
|
|
289
|
+
// Stabilize variables to prevent unnecessary re-fetches
|
|
290
|
+
const stableVariables = useStableVariables(props.variables);
|
|
291
|
+
// Manage abort controller for cancellable requests
|
|
292
|
+
const { abortSignal } = useAbortableRequest();
|
|
197
293
|
const internalProps = useMemo(() => {
|
|
198
294
|
return {
|
|
199
295
|
...props,
|
|
@@ -206,7 +302,7 @@ const usePaginationQuery = (document, props) => {
|
|
|
206
302
|
...internalProps.context,
|
|
207
303
|
fetchOptions: {
|
|
208
304
|
...internalProps.context?.fetchOptions,
|
|
209
|
-
signal:
|
|
305
|
+
signal: abortSignal,
|
|
210
306
|
},
|
|
211
307
|
},
|
|
212
308
|
pollInterval: internalProps.pollInterval,
|
|
@@ -214,7 +310,7 @@ const usePaginationQuery = (document, props) => {
|
|
|
214
310
|
onCompleted: completedData => {
|
|
215
311
|
if (networkStatus === NetworkStatus.refetch) {
|
|
216
312
|
// trigger reset for refetchQueries for the provided document.
|
|
217
|
-
|
|
313
|
+
dispatch({ type: "INCREMENT_RESET_TRIGGER" });
|
|
218
314
|
}
|
|
219
315
|
if (internalProps.onCompleted) {
|
|
220
316
|
internalProps.onCompleted(completedData);
|
|
@@ -226,15 +322,14 @@ const usePaginationQuery = (document, props) => {
|
|
|
226
322
|
nextFetchPolicy: "network-only",
|
|
227
323
|
initialFetchPolicy: "network-only",
|
|
228
324
|
});
|
|
229
|
-
const [data, setData] = useState();
|
|
230
325
|
const onReset = useCallback(() => {
|
|
231
|
-
|
|
326
|
+
dispatch({ type: "INCREMENT_RESET_TRIGGER" });
|
|
232
327
|
}, []);
|
|
233
328
|
useEffect(() => {
|
|
234
329
|
onReset();
|
|
235
330
|
}, [document, onReset]);
|
|
236
331
|
const { table: { setIsLoading, isLoading, setPageInfo, pageInfo, reset, nextPage, previousPage }, variables: { first, after, last, before }, } = useRelayPagination({
|
|
237
|
-
pageSize: internalProps.pageSize
|
|
332
|
+
pageSize: internalProps.pageSize ?? internalProps.variables?.first ?? defaultPageSize,
|
|
238
333
|
onReset,
|
|
239
334
|
});
|
|
240
335
|
const doFetchMore = useCallback((variables, prev) => {
|
|
@@ -243,47 +338,25 @@ const usePaginationQuery = (document, props) => {
|
|
|
243
338
|
return;
|
|
244
339
|
}
|
|
245
340
|
setIsLoading(true);
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
*/
|
|
249
|
-
const fetchMoreVariables = {
|
|
250
|
-
...internalProps.variables,
|
|
251
|
-
...(internalProps.variables && "page" in internalProps.variables && "pageSize" in internalProps.variables
|
|
252
|
-
? {
|
|
253
|
-
pageSize: variables.first,
|
|
254
|
-
page: Number(variables.after) || 0,
|
|
255
|
-
}
|
|
256
|
-
: { ...variables }),
|
|
257
|
-
};
|
|
341
|
+
// Convert pagination variables based on pagination type (cursor vs page-based)
|
|
342
|
+
const fetchMoreVariables = convertPaginationVariables(internalProps.variables, variables);
|
|
258
343
|
fetchMore({
|
|
259
344
|
variables: fetchMoreVariables,
|
|
260
|
-
updateQuery: (
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
}
|
|
270
|
-
return undefined;
|
|
271
|
-
}
|
|
272
|
-
// Safely handle Apollo types
|
|
273
|
-
const typedResult = fetchMoreResult;
|
|
274
|
-
setLastFetchedData(typedResult);
|
|
275
|
-
const result = internalProps.updateQuery(prev, typedResult);
|
|
276
|
-
setPageInfo(result.pageInfo || null);
|
|
277
|
-
setData(result.data);
|
|
278
|
-
setIsLoading(false);
|
|
279
|
-
return result.data;
|
|
280
|
-
},
|
|
345
|
+
updateQuery: createUpdateQueryHandler({
|
|
346
|
+
abortSignal,
|
|
347
|
+
prev,
|
|
348
|
+
onUpdate: internalProps.updateQuery,
|
|
349
|
+
onDataUpdate: (data) => dispatch({ type: "SET_DATA", payload: data }),
|
|
350
|
+
onLastFetchedUpdate: (data) => dispatch({ type: "SET_LAST_FETCHED_DATA", payload: data }),
|
|
351
|
+
onPageInfoUpdate: setPageInfo,
|
|
352
|
+
onLoadingComplete: () => setIsLoading(false),
|
|
353
|
+
}),
|
|
281
354
|
// It is apparently not possible to use the onError from the useLazyQuery hook so we have to handle it here.
|
|
282
355
|
// However, if you need to pass in your own onError function, you can do so in the props of the hook.
|
|
283
356
|
// But we ignore the error if the request was aborted.
|
|
284
357
|
}).catch(error => {
|
|
285
358
|
setIsLoading(false);
|
|
286
|
-
if (
|
|
359
|
+
if (abortSignal.aborted) {
|
|
287
360
|
return;
|
|
288
361
|
}
|
|
289
362
|
if (internalProps.onError) {
|
|
@@ -293,35 +366,18 @@ const usePaginationQuery = (document, props) => {
|
|
|
293
366
|
throw error;
|
|
294
367
|
}
|
|
295
368
|
});
|
|
296
|
-
}, [internalProps, setIsLoading, fetchMore,
|
|
369
|
+
}, [internalProps, setIsLoading, fetchMore, abortSignal, setPageInfo]);
|
|
297
370
|
useEffect(() => {
|
|
298
|
-
|
|
371
|
+
dispatch({ type: "RESET" });
|
|
299
372
|
reset();
|
|
300
|
-
}, [
|
|
301
|
-
//
|
|
302
|
-
const
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
beforeRef.current = before;
|
|
309
|
-
}, [before]);
|
|
310
|
-
const firstRef = useRef(first);
|
|
311
|
-
useEffect(() => {
|
|
312
|
-
firstRef.current = first;
|
|
313
|
-
}, [first]);
|
|
314
|
-
// Use a ref to track the current data
|
|
315
|
-
const dataRef = useRef(data);
|
|
316
|
-
useEffect(() => {
|
|
317
|
-
dataRef.current = data;
|
|
318
|
-
}, [data]);
|
|
319
|
-
// Store doFetchMore in a ref to avoid dependency cycles
|
|
320
|
-
const doFetchMoreRef = useRef(doFetchMore);
|
|
321
|
-
useEffect(() => {
|
|
322
|
-
doFetchMoreRef.current = doFetchMore;
|
|
323
|
-
}, [doFetchMore]);
|
|
324
|
-
// Stabilize the fetchMore call by using refs instead of direct dependencies
|
|
373
|
+
}, [stableVariables, reset]);
|
|
374
|
+
// Store pagination values in refs to avoid triggering unnecessary effect re-runs
|
|
375
|
+
const firstRef = useSyncedRef(first);
|
|
376
|
+
const lastRef = useSyncedRef(last);
|
|
377
|
+
const beforeRef = useSyncedRef(before);
|
|
378
|
+
const dataRef = useSyncedRef(state.data);
|
|
379
|
+
const doFetchMoreRef = useSyncedRef(doFetchMore);
|
|
380
|
+
// Fetch initial page when variables or reset trigger changes
|
|
325
381
|
useEffect(() => {
|
|
326
382
|
const fetchVariables = {
|
|
327
383
|
first: firstRef.current,
|
|
@@ -329,30 +385,34 @@ const usePaginationQuery = (document, props) => {
|
|
|
329
385
|
before: undefined,
|
|
330
386
|
after: undefined,
|
|
331
387
|
};
|
|
332
|
-
// Use the ref version to avoid dependency cycles
|
|
333
388
|
doFetchMoreRef.current(fetchVariables, undefined);
|
|
334
|
-
//
|
|
335
|
-
}, [
|
|
336
|
-
//
|
|
389
|
+
// Refs are stable and don't need to trigger re-runs, but included to satisfy linter
|
|
390
|
+
}, [stableVariables, state.resetTrigger, firstRef, doFetchMoreRef]);
|
|
391
|
+
// Fetch next/previous page when after cursor changes
|
|
337
392
|
useEffect(() => {
|
|
338
|
-
if (after) {
|
|
339
|
-
const fetchVariables = {
|
|
340
|
-
|
|
393
|
+
if (after !== undefined && after !== null) {
|
|
394
|
+
const fetchVariables = {
|
|
395
|
+
first: firstRef.current,
|
|
396
|
+
after,
|
|
397
|
+
last: lastRef.current,
|
|
398
|
+
before: beforeRef.current,
|
|
399
|
+
};
|
|
341
400
|
doFetchMoreRef.current(fetchVariables, dataRef.current);
|
|
342
401
|
}
|
|
343
|
-
//
|
|
344
|
-
}, [after]);
|
|
402
|
+
// Refs are stable and don't need to trigger re-runs, but included to satisfy linter
|
|
403
|
+
}, [after, firstRef, lastRef, beforeRef, dataRef, doFetchMoreRef]);
|
|
345
404
|
return useMemo(() => {
|
|
346
405
|
return {
|
|
347
|
-
data: data
|
|
406
|
+
data: state.data ?? previousData,
|
|
348
407
|
previousData,
|
|
349
408
|
loading: isLoading || lazyLoading,
|
|
350
409
|
pagination: { setIsLoading, isLoading, setPageInfo, pageInfo, reset, nextPage, previousPage },
|
|
351
|
-
lastFetchedData,
|
|
410
|
+
lastFetchedData: state.lastFetchedData,
|
|
352
411
|
reset,
|
|
353
412
|
};
|
|
354
413
|
}, [
|
|
355
|
-
data,
|
|
414
|
+
state.data,
|
|
415
|
+
state.lastFetchedData,
|
|
356
416
|
isLoading,
|
|
357
417
|
lazyLoading,
|
|
358
418
|
setIsLoading,
|
|
@@ -361,7 +421,6 @@ const usePaginationQuery = (document, props) => {
|
|
|
361
421
|
reset,
|
|
362
422
|
nextPage,
|
|
363
423
|
previousPage,
|
|
364
|
-
lastFetchedData,
|
|
365
424
|
previousData,
|
|
366
425
|
]);
|
|
367
426
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trackunit/react-graphql-hooks",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.12",
|
|
4
4
|
"repository": "https://github.com/Trackunit/manager",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"engines": {
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"@apollo/client": "3.13.8",
|
|
11
11
|
"react": "19.0.0",
|
|
12
|
-
"@trackunit/i18n-library-translation": "1.9.
|
|
13
|
-
"@trackunit/shared-utils": "1.11.
|
|
12
|
+
"@trackunit/i18n-library-translation": "1.9.13",
|
|
13
|
+
"@trackunit/shared-utils": "1.11.10",
|
|
14
14
|
"es-toolkit": "^1.39.10",
|
|
15
|
-
"@trackunit/react-components": "1.
|
|
15
|
+
"@trackunit/react-components": "1.13.0"
|
|
16
16
|
},
|
|
17
17
|
"module": "./index.esm.js",
|
|
18
18
|
"main": "./index.cjs.js",
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { OperationVariables as ApolloOperationVariables } from "@apollo/client/core/types";
|
|
2
|
+
import { RelayPageInfo } from "@trackunit/react-components";
|
|
3
|
+
type RelayPaginationQueryVariables = {
|
|
4
|
+
first?: number | null;
|
|
5
|
+
last?: number | null;
|
|
6
|
+
before?: string | null;
|
|
7
|
+
after?: string | null;
|
|
8
|
+
};
|
|
9
|
+
export type PaginationState<TData> = {
|
|
10
|
+
data: TData | undefined;
|
|
11
|
+
lastFetchedData: TData | undefined;
|
|
12
|
+
resetTrigger: number;
|
|
13
|
+
};
|
|
14
|
+
export type PaginationAction<TData> = {
|
|
15
|
+
type: "SET_DATA";
|
|
16
|
+
payload: TData;
|
|
17
|
+
} | {
|
|
18
|
+
type: "SET_LAST_FETCHED_DATA";
|
|
19
|
+
payload: TData;
|
|
20
|
+
} | {
|
|
21
|
+
type: "RESET";
|
|
22
|
+
} | {
|
|
23
|
+
type: "INCREMENT_RESET_TRIGGER";
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Converts pagination variables from cursor-based (first/after) to page-based (page/pageSize) if needed.
|
|
27
|
+
* Returns the appropriate variables based on the pagination type.
|
|
28
|
+
*/
|
|
29
|
+
export declare const convertPaginationVariables: <TVariables extends ApolloOperationVariables>(baseVariables: TVariables | undefined, paginationVars: RelayPaginationQueryVariables) => TVariables;
|
|
30
|
+
/**
|
|
31
|
+
* Creates an update query handler for Apollo's fetchMore.
|
|
32
|
+
* Handles aborted requests and merges new data with existing data.
|
|
33
|
+
*/
|
|
34
|
+
export declare const createUpdateQueryHandler: <TData, TPreviousResult>(params: {
|
|
35
|
+
abortSignal: AbortSignal;
|
|
36
|
+
prev: TData | undefined;
|
|
37
|
+
onUpdate: (prev: TData | undefined, newData: TData) => {
|
|
38
|
+
data: TData;
|
|
39
|
+
pageInfo?: RelayPageInfo | null;
|
|
40
|
+
};
|
|
41
|
+
onDataUpdate: (data: TData) => void;
|
|
42
|
+
onLastFetchedUpdate: (data: TData) => void;
|
|
43
|
+
onPageInfoUpdate: (pageInfo: RelayPageInfo | null) => void;
|
|
44
|
+
onLoadingComplete: () => void;
|
|
45
|
+
}) => (_previousResult: TPreviousResult, { fetchMoreResult }: {
|
|
46
|
+
fetchMoreResult?: unknown;
|
|
47
|
+
}) => TPreviousResult;
|
|
48
|
+
/**
|
|
49
|
+
* Creates a reducer function for managing pagination state.
|
|
50
|
+
* Handles data updates, reset, and reset trigger increments.
|
|
51
|
+
*/
|
|
52
|
+
export declare const createPaginationReducer: <TData>() => (state: PaginationState<TData>, action: PaginationAction<TData>) => PaginationState<TData>;
|
|
53
|
+
export {};
|
|
@@ -45,17 +45,15 @@ export interface PaginationQueryProps<TData, TVariables extends ApolloOperationV
|
|
|
45
45
|
* lastFetchedData is used to store the last fetched data, so you can update data according to last page.
|
|
46
46
|
*
|
|
47
47
|
* @example
|
|
48
|
-
*
|
|
49
48
|
* const {
|
|
50
49
|
* data,
|
|
51
50
|
* loading,
|
|
52
51
|
* pagination,
|
|
53
52
|
* lastFetchedData,
|
|
54
|
-
*} = usePaginationQuery({
|
|
55
|
-
* query: myLazyQuery, // <-- myLazyQuery is the graphql LazyQuery to run pagination for.
|
|
53
|
+
* } = usePaginationQuery(MyAssetsDocument, {
|
|
56
54
|
* updateQuery: (previous, newData) => {
|
|
57
|
-
*
|
|
58
|
-
*
|
|
55
|
+
* // Here you can use the unionEdgesByNodeKey utils to merge your edges together.
|
|
56
|
+
* if (newData?.assets?.edges) {
|
|
59
57
|
* return {
|
|
60
58
|
* data: {
|
|
61
59
|
* ...newData,
|
|
@@ -70,11 +68,11 @@ export interface PaginationQueryProps<TData, TVariables extends ApolloOperationV
|
|
|
70
68
|
* return { data: newData, pageInfo: newData.assets.pageInfo };
|
|
71
69
|
* },
|
|
72
70
|
* });
|
|
73
|
-
* @template TData
|
|
74
|
-
* @template TVariables
|
|
75
|
-
* @param
|
|
76
|
-
* @param
|
|
77
|
-
* @returns {
|
|
71
|
+
* @template TData - The type of the query result data.
|
|
72
|
+
* @template TVariables - The type of the query variables.
|
|
73
|
+
* @param document - The GraphQL query document.
|
|
74
|
+
* @param props - The properties for configuring the query. This includes the `updateQuery` function for merging new and existing data, and options for pagination such as `pageSize`. Also includes other lazy query hook options from Apollo Client.
|
|
75
|
+
* @returns {PaginationQuery<TData>} The pagination query result containing data, loading state, pagination controls, and lastFetchedData.
|
|
78
76
|
*/
|
|
79
77
|
export declare const usePaginationQuery: <TData, TVariables extends ApolloOperationVariables>(document: TypedDocumentNode<TData, TVariables>, props: PaginationQueryProps<TData, TVariables>) => PaginationQuery<TData>;
|
|
80
78
|
export {};
|