@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.1 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_tsx_1 = require("./react-query/QueryClientProvider.js");
const QueryErrorResetBoundary_tsx_1 = require("./react-query/QueryErrorResetBoundary.js");
const errorBoundaryUtils_ts_1 = require("./react-query/errorBoundaryUtils.js");
const isRestoring_tsx_1 = require("./react-query/isRestoring.js");
const suspense_ts_1 = require("./react-query/suspense.js");
const useObserver_ts_1 = require("./useObserver.js");
const utils_ts_1 = require("./utils.js");
const unified_signals_1 = require("@preact-signals/unified-signals");
const utils_1 = 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_ts_1.useRefBasedOptions)(options);
const $queryClient = (0, QueryClientProvider_tsx_1.useQueryClient$)({
context: (0, hooks_1.useComputedOnce)(() => $options.value.context).value,
});
const $isRestoring = (0, isRestoring_tsx_1.useIsRestoring$)();
const $errorBoundary = (0, QueryErrorResetBoundary_tsx_1.useQueryErrorResetBoundary$)();
const $suspenseBehavior = (0, utils_1.$)(() => $options.value.suspenseBehavior ?? "load-on-access");
const $defaultedOptions = (0, hooks_1.useComputedOnce)(() => {
const defaulted = (0, utils_ts_1.wrapFunctionsInUntracked)($queryClient.value.defaultQueryOptions($options.value));
defaulted._optimisticResults = $isRestoring.value
? "isRestoring"
: "optimistic";
(0, suspense_ts_1.ensureStaleTime)(defaulted);
(0, errorBoundaryUtils_ts_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_ts_1.useObserverStore)(() => ({
getCurrent: () => $observer.value.getOptimisticResult($defaultedOptions.value),
subscribe: (emit) => $observer.value.subscribe((newValue) => {
emit(newValue);
}),
}));
(0, errorBoundaryUtils_ts_1.useClearResetErrorBoundary$)($errorBoundary);
const $shouldSuspend = (0, utils_1.$)(() => (0, suspense_ts_1.shouldSuspend)($defaultedOptions.value, state, $isRestoring.value));
const getData = () => {
if ((0, errorBoundaryUtils_ts_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