87 lines
2.4 KiB
JavaScript
87 lines
2.4 KiB
JavaScript
import { useRef, useCallback, useEffect } from 'react';
|
|
import { isEqual } from 'lodash';
|
|
|
|
import api from 'shared/utils/api';
|
|
import useMergeState from 'shared/hooks/mergeState';
|
|
import useDeepCompareMemoize from 'shared/hooks/deepCompareMemoize';
|
|
|
|
const useQuery = (url, propsVariables = {}, options = {}) => {
|
|
const { lazy = false, cachePolicy = 'cache-first' } = options;
|
|
|
|
const wasCalled = useRef(false);
|
|
const propsVariablesMemoized = useDeepCompareMemoize(propsVariables);
|
|
|
|
const isSleeping = lazy && !wasCalled.current;
|
|
const isCacheAvailable = cache[url] && isEqual(cache[url].apiVariables, propsVariables);
|
|
const canUseCache = isCacheAvailable && cachePolicy !== 'no-cache' && !wasCalled.current;
|
|
|
|
const [state, mergeState] = useMergeState({
|
|
data: canUseCache ? cache[url].data : null,
|
|
error: null,
|
|
isLoading: !lazy && !canUseCache,
|
|
variables: {},
|
|
});
|
|
|
|
const makeRequest = useCallback(
|
|
(newVariables, { skipLoading } = {}) => {
|
|
const variables = { ...state.variables, ...(newVariables || {}) };
|
|
const apiVariables = { ...propsVariablesMemoized, ...variables };
|
|
|
|
if (!skipLoading) {
|
|
mergeState({ isLoading: true, variables });
|
|
} else if (newVariables) {
|
|
mergeState({ variables });
|
|
}
|
|
|
|
api.get(url, apiVariables).then(
|
|
data => {
|
|
cache[url] = { data, apiVariables };
|
|
mergeState({ data, error: null, isLoading: false });
|
|
},
|
|
error => {
|
|
mergeState({ error, data: null, isLoading: false });
|
|
},
|
|
);
|
|
|
|
wasCalled.current = true;
|
|
},
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
[propsVariablesMemoized],
|
|
);
|
|
|
|
useEffect(() => {
|
|
if (isSleeping) return;
|
|
if (canUseCache && cachePolicy === 'cache-only') return;
|
|
|
|
makeRequest(
|
|
{},
|
|
{
|
|
skipLoading: canUseCache && cachePolicy === 'cache-first',
|
|
},
|
|
);
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [makeRequest]);
|
|
|
|
const setLocalData = useCallback(
|
|
getUpdatedData =>
|
|
mergeState(({ data }) => {
|
|
cache[url] = { ...(cache[url] || {}), data: getUpdatedData(data) };
|
|
return { data: getUpdatedData(data) };
|
|
}),
|
|
[mergeState, url],
|
|
);
|
|
|
|
return [
|
|
{
|
|
...state,
|
|
variables: { ...propsVariablesMemoized, ...state.variables },
|
|
setLocalData,
|
|
},
|
|
makeRequest,
|
|
];
|
|
};
|
|
|
|
const cache = {};
|
|
|
|
export default useQuery;
|