@preact-signals/query
Version:
A reactive utility for React/Preact that simplifies the handling of data fetching and state management. Powered by Preact Signals, it provides hooks and functions to create reactive resources and manage their state seamlessly.
116 lines • 5.02 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createBaseQuery = void 0;
const hooks_1 = require("@preact-signals/utils/hooks");
const react_1 = require("react");
const QueryClientProvider_1 = require("./react-query/QueryClientProvider");
const QueryErrorResetBoundary_1 = require("./react-query/QueryErrorResetBoundary");
const errorBoundaryUtils_1 = require("./react-query/errorBoundaryUtils");
const isRestoring_1 = require("./react-query/isRestoring");
const suspense_1 = require("./react-query/suspense");
const useObserver_1 = require("./useObserver");
const utils_1 = require("./utils");
const unified_signals_1 = require("@preact-signals/unified-signals");
const utils_2 = require("@preact-signals/utils");
var ReturnStatus;
(function (ReturnStatus) {
ReturnStatus[ReturnStatus["Error"] = 0] = "Error";
ReturnStatus[ReturnStatus["Success"] = 1] = "Success";
ReturnStatus[ReturnStatus["Suspense"] = 2] = "Suspense";
})(ReturnStatus || (ReturnStatus = {}));
const createBaseQuery = (Observer) => (options) => {
const $options = (0, utils_1.useRefBasedOptions)(options);
const $queryClient = (0, QueryClientProvider_1.useQueryClient$)({
context: (0, hooks_1.useComputedOnce)(() => $options.value.context).value,
});
const $isRestoring = (0, isRestoring_1.useIsRestoring$)();
const $errorBoundary = (0, QueryErrorResetBoundary_1.useQueryErrorResetBoundary$)();
const $suspenseBehavior = (0, utils_2.$)(() => $options.value.suspenseBehavior ?? "load-on-access");
const $defaultedOptions = (0, hooks_1.useComputedOnce)(() => {
const defaulted = (0, utils_1.wrapFunctionsInUntracked)($queryClient.value.defaultQueryOptions($options.value));
defaulted._optimisticResults = $isRestoring.value
? "isRestoring"
: "optimistic";
(0, suspense_1.ensureStaleTime)(defaulted);
(0, errorBoundaryUtils_1.ensurePreventErrorBoundaryRetry)(defaulted, $errorBoundary.value);
return defaulted;
});
const $observer = (0, hooks_1.useComputedOnce)(() => new Observer($queryClient.value, $defaultedOptions.peek()));
(0, hooks_1.useSignalEffectOnce)(() => {
$observer.value.setOptions($defaultedOptions.value);
});
const state = (0, useObserver_1.useObserverStore)(() => ({
getCurrent: () => $observer.value.getOptimisticResult($defaultedOptions.value),
subscribe: (emit) => $observer.value.subscribe((newValue) => {
emit(newValue);
}),
}));
(0, errorBoundaryUtils_1.useClearResetErrorBoundary$)($errorBoundary);
const $shouldSuspend = (0, utils_2.$)(() => (0, suspense_1.shouldSuspend)($defaultedOptions.value, state, $isRestoring.value));
const getData = () => {
if ((0, errorBoundaryUtils_1.getHasError)({
result: state,
errorResetBoundary: $errorBoundary.value,
query: $observer.value.getCurrentQuery(),
useErrorBoundary: $defaultedOptions.value.useErrorBoundary,
})) {
return {
type: ReturnStatus.Error,
data: state.error,
};
}
if ($shouldSuspend.value) {
// will not refetch if already fetching
// should suspend is not using data, so all will work fine
return {
type: ReturnStatus.Suspense,
data: $observer.value.fetchOptimistic($defaultedOptions.value),
};
}
return {
type: ReturnStatus.Success,
data: state.data,
};
};
const dataComputed = (0, hooks_1.useComputedOnce)(() => {
const res = getData();
if (res.type === ReturnStatus.Success) {
return res.data;
}
throw res.data;
});
(0, unified_signals_1.untracked)(() => {
if ($shouldSuspend.value &&
$suspenseBehavior.value !== "load-on-access") {
const data = getData();
if (data.type === ReturnStatus.Suspense &&
$suspenseBehavior.value === "suspend-eagerly") {
throw data.data;
}
}
});
const willSuspendOrThrow = (0, hooks_1.useComputedOnce)(() => {
if (!$shouldSuspend.value ||
$suspenseBehavior.value !== "suspend-eagerly") {
return false;
}
return getData().type !== ReturnStatus.Success;
});
willSuspendOrThrow.value;
// @ts-expect-error actually it can be written
state.dataSafe = undefined;
return (0, react_1.useMemo)(() => new Proxy(state, {
get(target, prop) {
if (prop === "data") {
return dataComputed.value;
}
if (prop === "dataSafe") {
return target.data;
}
// @ts-expect-error
return Reflect.get(...arguments);
},
}), []);
};
exports.createBaseQuery = createBaseQuery;
//# sourceMappingURL=createBaseQuery$.js.map