@hazae41/glacier
Version:
Yet another React data (re)fetching library
298 lines (294 loc) • 11.9 kB
JavaScript
'use strict';
var option = require('@hazae41/option');
var result = require('@hazae41/result');
var arrays = require('../../../../libs/arrays/arrays.cjs');
var ref = require('../../../../libs/react/ref.cjs');
var index = require('../../../../libs/request/index.cjs');
var index$1 = require('../../../../libs/signals/index.cjs');
var time = require('../../../../libs/time/time.cjs');
var core = require('../../../core/core.cjs');
var helper = require('../../../queries/scroll/helper.cjs');
var react = require('react');
function useScrollableQuery(factory, deps) {
const query = react.useMemo(() => {
return factory(...deps);
}, deps);
if (query == null)
return useSkeletonScrollableQuery();
if (query.settings.fetcher == null)
return useFetcherlessScrollableQuery(query.settings);
return useFetcherfulScrollableQuery(query.settings);
}
function useSkeletonScrollableQuery() {
ref.useRenderRef(undefined);
const cacheKey = react.useMemo(() => {
// NOOP
}, [undefined]);
react.useState(0);
react.useRef();
react.useRef();
react.useMemo(() => {
// NOOP
}, [cacheKey]);
react.useCallback(() => {
// NOOP
}, [cacheKey]);
react.useCallback(() => {
// NOOP
}, [cacheKey]);
react.useEffect(() => {
// NOOP
}, [cacheKey]);
react.useEffect(() => {
// NOOP
}, [cacheKey]);
const mutateOrThrow = react.useCallback(async (mutator) => {
throw new core.MissingKeyError();
}, [cacheKey]);
const deleteOrThrow = react.useCallback(async () => {
throw new core.MissingKeyError();
}, [cacheKey]);
const fetchOrThrow = react.useCallback(async (init) => {
throw new core.MissingKeyError();
}, [cacheKey]);
const refetchOrThrow = react.useCallback(async (init) => {
throw new core.MissingKeyError();
}, [cacheKey]);
const scrollOrThrow = react.useCallback(async (init) => {
throw new core.MissingKeyError();
}, [cacheKey]);
const peekOrNull = react.useCallback(() => {
return undefined;
}, [undefined, undefined]);
return { mutateOrThrow, deleteOrThrow, fetchOrThrow, refetchOrThrow, scrollOrThrow, peekOrNull };
}
/**
* Scroll query
* @param scroller
* @param fetcher
* @param settings
* @returns
*/
function useFetcherlessScrollableQuery(settings) {
const settingsRef = ref.useRenderRef(settings);
const cacheKey = react.useMemo(() => {
return helper.Scrollable.getCacheKey(settings.key);
}, [settings.key]);
const [, setCounter] = react.useState(0);
const stateRef = react.useRef();
const aborterRef = react.useRef();
react.useMemo(() => {
stateRef.current = core.core.getStateSync(cacheKey);
aborterRef.current = core.core.getAborterSync(cacheKey);
}, [cacheKey]);
const setState = react.useCallback((state) => {
stateRef.current = state;
setCounter(c => c + 1);
}, [cacheKey]);
const setAborter = react.useCallback((aborter) => {
aborterRef.current = aborter;
setCounter(c => c + 1);
}, [cacheKey]);
react.useEffect(() => {
if (stateRef.current != null)
return;
core.core.getOrThrow(cacheKey, settingsRef.current).then(setState).catch(console.warn);
}, [cacheKey]);
react.useEffect(() => {
const onState = () => {
core.core.getOrThrow(cacheKey, settingsRef.current).then(setState).catch(console.warn);
return new option.None();
};
const onAborter = () => {
setAborter(core.core.getAborterSync(cacheKey));
return new option.None();
};
core.core.onState.on(cacheKey, onState, { passive: true });
core.core.onAborter.on(cacheKey, onAborter, { passive: true });
core.core.increment(cacheKey, settingsRef.current);
return () => {
core.core.decrementOrThrow(cacheKey, settingsRef.current);
core.core.onState.off(cacheKey, onState);
core.core.onAborter.off(cacheKey, onAborter);
};
}, [cacheKey]);
const mutateOrThrow = react.useCallback(async (mutator) => {
return await core.core.mutateOrThrow(cacheKey, mutator, settingsRef.current);
}, [cacheKey]);
const deleteOrThrow = react.useCallback(async () => {
return await core.core.deleteOrThrow(cacheKey, settingsRef.current);
}, [cacheKey]);
const fetchOrThrow = react.useCallback(async (aborter = new AbortController()) => {
throw new core.MissingFetcherError();
}, [cacheKey]);
const refetchOrThrow = react.useCallback(async (aborter = new AbortController()) => {
throw new core.MissingFetcherError();
}, [cacheKey]);
const scrollOrThrow = react.useCallback(async (aborter = new AbortController()) => {
throw new core.MissingFetcherError();
}, [cacheKey]);
const state = stateRef.current;
const aborter = aborterRef.current;
const ready = state != null;
const fetching = aborter != null;
const optimistic = state?.isFake();
const current = state?.current;
const data = state?.data;
const error = state?.error;
const real = state?.real;
const fake = state?.fake;
const peekOrNull = react.useCallback(() => {
const pages = state?.real?.data?.get();
if (pages == null)
return undefined;
return settings.scroller(arrays.Arrays.last(pages));
}, [state?.real?.data, settings.scroller]);
return {
...settings,
cacheKey,
current,
data,
error,
real,
fake,
ready,
optimistic,
aborter,
fetching,
mutateOrThrow,
fetchOrThrow,
refetchOrThrow,
scrollOrThrow,
deleteOrThrow,
peekOrNull,
};
}
function useFetcherfulScrollableQuery(settings) {
const settingsRef = ref.useRenderRef(settings);
const cacheKey = react.useMemo(() => {
return helper.Scrollable.getCacheKey(settings.key);
}, [settings.key]);
const [, setCounter] = react.useState(0);
const stateRef = react.useRef();
const aborterRef = react.useRef();
react.useMemo(() => {
stateRef.current = core.core.getStateSync(cacheKey);
aborterRef.current = core.core.getAborterSync(cacheKey);
}, [cacheKey]);
const setState = react.useCallback((state) => {
stateRef.current = state;
setCounter(c => c + 1);
}, [cacheKey]);
const setAborter = react.useCallback((aborter) => {
aborterRef.current = aborter;
setCounter(c => c + 1);
}, [cacheKey]);
react.useEffect(() => {
if (stateRef.current != null)
return;
core.core.getOrThrow(cacheKey, settingsRef.current).then(setState).catch(console.warn);
}, [cacheKey]);
react.useEffect(() => {
const onState = () => {
core.core.getOrThrow(cacheKey, settingsRef.current).then(setState).catch(console.warn);
return new option.None();
};
const onAborter = () => {
setAborter(core.core.getAborterSync(cacheKey));
return new option.None();
};
core.core.onState.on(cacheKey, onState, { passive: true });
core.core.onAborter.on(cacheKey, onAborter, { passive: true });
core.core.increment(cacheKey, settingsRef.current);
return () => {
core.core.decrementOrThrow(cacheKey, settingsRef.current);
core.core.onState.off(cacheKey, onState);
core.core.onAborter.off(cacheKey, onAborter);
};
}, [cacheKey]);
const mutateOrThrow = react.useCallback(async (mutator) => {
return await core.core.mutateOrThrow(cacheKey, mutator, settingsRef.current);
}, [cacheKey]);
const deleteOrThrow = react.useCallback(async () => {
return await core.core.deleteOrThrow(cacheKey, settingsRef.current);
}, [cacheKey]);
const fetchOrThrow = react.useCallback(async (init) => {
const state = stateRef.current;
const settings = settingsRef.current;
if (index.shouldUseCacheIfFresh(init?.cache) && time.Time.isAfterNow(state?.real?.current.cooldown))
return new result.Err(state);
if (index.shouldUseCacheIfStale(init?.cache) && time.Time.isAfterNow(state?.real?.current.expiration))
return new result.Err(state);
if (!index.shouldUseNetwork(init?.cache))
throw new Error(`Could not fetch using the provided cache directive`);
const aborter = new AbortController();
const signal = AbortSignal.any([aborter.signal, index$1.AbortSignals.getOrNever(init?.signal)]);
return new result.Ok(await core.core.runOrJoin(cacheKey, aborter, () => helper.Scrollable.fetchOrThrow(cacheKey, signal, settings)));
}, [cacheKey]);
const refetchOrThrow = react.useCallback(async (init) => {
const state = stateRef.current;
const settings = settingsRef.current;
if (index.shouldUseCacheIfFresh(init?.cache) && time.Time.isAfterNow(state?.real?.current.cooldown))
return new result.Err(state);
if (index.shouldUseCacheIfStale(init?.cache) && time.Time.isAfterNow(state?.real?.current.expiration))
return new result.Err(state);
if (!index.shouldUseNetwork(init?.cache))
throw new Error(`Could not fetch using the provided cache directive`);
const aborter = new AbortController();
const signal = AbortSignal.any([aborter.signal, index$1.AbortSignals.getOrNever(init?.signal)]);
return new result.Ok(await core.core.runOrReplace(cacheKey, aborter, () => helper.Scrollable.fetchOrThrow(cacheKey, signal, settings)));
}, [cacheKey]);
const scrollOrThrow = react.useCallback(async (init) => {
const state = stateRef.current;
const settings = settingsRef.current;
if (index.shouldUseCacheIfFresh(init?.cache) && time.Time.isAfterNow(state?.real?.current.cooldown))
return new result.Err(state);
if (index.shouldUseCacheIfStale(init?.cache) && time.Time.isAfterNow(state?.real?.current.expiration))
return new result.Err(state);
if (!index.shouldUseNetwork(init?.cache))
throw new Error(`Could not fetch using the provided cache directive`);
const aborter = new AbortController();
const signal = AbortSignal.any([aborter.signal, index$1.AbortSignals.getOrNever(init?.signal)]);
return new result.Ok(await core.core.runOrReplace(cacheKey, aborter, () => helper.Scrollable.scrollOrThrow(cacheKey, signal, settings)));
}, [cacheKey]);
const state = stateRef.current;
const aborter = aborterRef.current;
const ready = state != null;
const fetching = aborter != null;
const optimistic = state?.isFake();
const current = state?.current;
const data = state?.data;
const error = state?.error;
const real = state?.real;
const fake = state?.fake;
const peekOrNull = react.useCallback(() => {
const pages = state?.real?.data?.get();
if (pages == null)
return undefined;
return settings.scroller(arrays.Arrays.last(pages));
}, [state?.real?.data, settings.scroller]);
return {
...settings,
cacheKey,
current,
data,
error,
real,
fake,
ready,
optimistic,
aborter,
fetching,
mutateOrThrow,
fetchOrThrow,
refetchOrThrow,
scrollOrThrow,
deleteOrThrow,
peekOrNull
};
}
exports.useFetcherfulScrollableQuery = useFetcherfulScrollableQuery;
exports.useFetcherlessScrollableQuery = useFetcherlessScrollableQuery;
exports.useScrollableQuery = useScrollableQuery;
exports.useSkeletonScrollableQuery = useSkeletonScrollableQuery;
//# sourceMappingURL=scroll.cjs.map