* feat(#638): add pagination support to data-provider * feat(#638): use infinite rowModelType in market list table * chore(#638): code style fixes * feat(#638): fix data provider post update callbacks, handle market list table empty data * feat(#638): amend variable names to improve code readability
96 lines
3.1 KiB
TypeScript
96 lines
3.1 KiB
TypeScript
import { useState, useEffect, useRef, useCallback } from 'react';
|
|
import { useApolloClient } from '@apollo/client';
|
|
import type { OperationVariables } from '@apollo/client';
|
|
import type { Subscribe, Pagination, Load } from '../lib/generic-data-provider';
|
|
|
|
/**
|
|
*
|
|
* @param dataProvider subscribe function created by makeDataProvider
|
|
* @param update optional function called on each delta received in subscription, if returns true updated data will be not passed from hook (component handles updates internally)
|
|
* @param variables optional
|
|
* @returns state: data, loading, error, methods: flush (pass updated data to update function without delta), restart: () => void}};
|
|
*/
|
|
export function useDataProvider<Data, Delta>({
|
|
dataProvider,
|
|
update,
|
|
insert,
|
|
variables,
|
|
}: {
|
|
dataProvider: Subscribe<Data, Delta>;
|
|
update?: ({ delta, data }: { delta: Delta; data: Data }) => boolean;
|
|
insert?: ({
|
|
insertionData,
|
|
data,
|
|
totalCount,
|
|
}: {
|
|
insertionData: Data;
|
|
data: Data;
|
|
totalCount?: number;
|
|
}) => boolean;
|
|
variables?: OperationVariables;
|
|
}) {
|
|
const client = useApolloClient();
|
|
const [data, setData] = useState<Data | null>(null);
|
|
const [totalCount, setTotalCount] = useState<number>();
|
|
const [loading, setLoading] = useState<boolean>(true);
|
|
const [error, setError] = useState<Error | undefined>(undefined);
|
|
const flushRef = useRef<(() => void) | undefined>(undefined);
|
|
const reloadRef = useRef<((force?: boolean) => void) | undefined>(undefined);
|
|
const loadRef = useRef<Load<Data> | undefined>(undefined);
|
|
const initialized = useRef<boolean>(false);
|
|
const flush = useCallback(() => {
|
|
if (flushRef.current) {
|
|
flushRef.current();
|
|
}
|
|
}, []);
|
|
const reload = useCallback((force = false) => {
|
|
if (reloadRef.current) {
|
|
reloadRef.current(force);
|
|
}
|
|
}, []);
|
|
const load = useCallback((pagination: Pagination) => {
|
|
if (loadRef.current) {
|
|
return loadRef.current(pagination);
|
|
}
|
|
return Promise.reject();
|
|
}, []);
|
|
const callback = useCallback(
|
|
({ data, error, loading, delta, insertionData, totalCount }) => {
|
|
setError(error);
|
|
setLoading(loading);
|
|
if (!error && !loading) {
|
|
// if update or insert function returns true it means that component handles updates
|
|
// component can use flush() which will call callback without delta and cause data state update
|
|
if (initialized.current) {
|
|
if (delta && update && update({ delta, data })) {
|
|
return;
|
|
}
|
|
if (
|
|
insertionData &&
|
|
insert &&
|
|
insert({ insertionData, data, totalCount })
|
|
) {
|
|
return;
|
|
}
|
|
}
|
|
initialized.current = true;
|
|
setTotalCount(totalCount);
|
|
setData(data);
|
|
}
|
|
},
|
|
[update, insert]
|
|
);
|
|
useEffect(() => {
|
|
const { unsubscribe, flush, reload, load } = dataProvider(
|
|
callback,
|
|
client,
|
|
variables
|
|
);
|
|
flushRef.current = flush;
|
|
reloadRef.current = reload;
|
|
loadRef.current = load;
|
|
return unsubscribe;
|
|
}, [client, initialized, dataProvider, callback, variables]);
|
|
return { data, loading, error, flush, reload, load, totalCount };
|
|
}
|