@tanstack/query-core
Version:
The framework agnostic core that powers TanStack Query
503 lines (502 loc) • 21.1 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __accessCheck = (obj, member, msg) => {
if (!member.has(obj))
throw TypeError("Cannot " + msg);
};
var __privateGet = (obj, member, getter) => {
__accessCheck(obj, member, "read from private field");
return getter ? getter.call(obj) : member.get(obj);
};
var __privateAdd = (obj, member, value) => {
if (member.has(obj))
throw TypeError("Cannot add the same private member more than once");
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
};
var __privateSet = (obj, member, value, setter) => {
__accessCheck(obj, member, "write to private field");
setter ? setter.call(obj, value) : member.set(obj, value);
return value;
};
var __privateMethod = (obj, member, method) => {
__accessCheck(obj, member, "access private method");
return method;
};
// src/queryObserver.ts
var queryObserver_exports = {};
__export(queryObserver_exports, {
QueryObserver: () => QueryObserver
});
module.exports = __toCommonJS(queryObserver_exports);
var import_utils = require("./utils.cjs");
var import_notifyManager = require("./notifyManager.cjs");
var import_focusManager = require("./focusManager.cjs");
var import_subscribable = require("./subscribable.cjs");
var import_retryer = require("./retryer.cjs");
var _client, _currentQuery, _currentQueryInitialState, _currentResult, _currentResultState, _currentResultOptions, _selectError, _selectFn, _selectResult, _lastQueryWithDefinedData, _staleTimeoutId, _refetchIntervalId, _currentRefetchInterval, _trackedProps, _executeFetch, executeFetch_fn, _updateStaleTimeout, updateStaleTimeout_fn, _computeRefetchInterval, computeRefetchInterval_fn, _updateRefetchInterval, updateRefetchInterval_fn, _updateTimers, updateTimers_fn, _clearStaleTimeout, clearStaleTimeout_fn, _clearRefetchInterval, clearRefetchInterval_fn, _updateQuery, updateQuery_fn, _notify, notify_fn;
var QueryObserver = class extends import_subscribable.Subscribable {
constructor(client, options) {
super();
__privateAdd(this, _executeFetch);
__privateAdd(this, _updateStaleTimeout);
__privateAdd(this, _computeRefetchInterval);
__privateAdd(this, _updateRefetchInterval);
__privateAdd(this, _updateTimers);
__privateAdd(this, _clearStaleTimeout);
__privateAdd(this, _clearRefetchInterval);
__privateAdd(this, _updateQuery);
__privateAdd(this, _notify);
__privateAdd(this, _client, void 0);
__privateAdd(this, _currentQuery, void 0);
__privateAdd(this, _currentQueryInitialState, void 0);
__privateAdd(this, _currentResult, void 0);
__privateAdd(this, _currentResultState, void 0);
__privateAdd(this, _currentResultOptions, void 0);
__privateAdd(this, _selectError, void 0);
__privateAdd(this, _selectFn, void 0);
__privateAdd(this, _selectResult, void 0);
// This property keeps track of the last query with defined data.
// It will be used to pass the previous data and query to the placeholder function between renders.
__privateAdd(this, _lastQueryWithDefinedData, void 0);
__privateAdd(this, _staleTimeoutId, void 0);
__privateAdd(this, _refetchIntervalId, void 0);
__privateAdd(this, _currentRefetchInterval, void 0);
__privateAdd(this, _trackedProps, /* @__PURE__ */ new Set());
__privateSet(this, _client, client);
this.options = options;
__privateSet(this, _selectError, null);
this.bindMethods();
this.setOptions(options);
}
bindMethods() {
this.refetch = this.refetch.bind(this);
}
onSubscribe() {
if (this.listeners.size === 1) {
__privateGet(this, _currentQuery).addObserver(this);
if (shouldFetchOnMount(__privateGet(this, _currentQuery), this.options)) {
__privateMethod(this, _executeFetch, executeFetch_fn).call(this);
}
__privateMethod(this, _updateTimers, updateTimers_fn).call(this);
}
}
onUnsubscribe() {
if (!this.hasListeners()) {
this.destroy();
}
}
shouldFetchOnReconnect() {
return shouldFetchOn(
__privateGet(this, _currentQuery),
this.options,
this.options.refetchOnReconnect
);
}
shouldFetchOnWindowFocus() {
return shouldFetchOn(
__privateGet(this, _currentQuery),
this.options,
this.options.refetchOnWindowFocus
);
}
destroy() {
this.listeners = /* @__PURE__ */ new Set();
__privateMethod(this, _clearStaleTimeout, clearStaleTimeout_fn).call(this);
__privateMethod(this, _clearRefetchInterval, clearRefetchInterval_fn).call(this);
__privateGet(this, _currentQuery).removeObserver(this);
}
setOptions(options, notifyOptions) {
const prevOptions = this.options;
const prevQuery = __privateGet(this, _currentQuery);
this.options = __privateGet(this, _client).defaultQueryOptions(options);
if (!(0, import_utils.shallowEqualObjects)(prevOptions, this.options)) {
__privateGet(this, _client).getQueryCache().notify({
type: "observerOptionsUpdated",
query: __privateGet(this, _currentQuery),
observer: this
});
}
if (typeof this.options.enabled !== "undefined" && typeof this.options.enabled !== "boolean") {
throw new Error("Expected enabled to be a boolean");
}
if (!this.options.queryKey) {
this.options.queryKey = prevOptions.queryKey;
}
__privateMethod(this, _updateQuery, updateQuery_fn).call(this);
const mounted = this.hasListeners();
if (mounted && shouldFetchOptionally(
__privateGet(this, _currentQuery),
prevQuery,
this.options,
prevOptions
)) {
__privateMethod(this, _executeFetch, executeFetch_fn).call(this);
}
this.updateResult(notifyOptions);
if (mounted && (__privateGet(this, _currentQuery) !== prevQuery || this.options.enabled !== prevOptions.enabled || this.options.staleTime !== prevOptions.staleTime)) {
__privateMethod(this, _updateStaleTimeout, updateStaleTimeout_fn).call(this);
}
const nextRefetchInterval = __privateMethod(this, _computeRefetchInterval, computeRefetchInterval_fn).call(this);
if (mounted && (__privateGet(this, _currentQuery) !== prevQuery || this.options.enabled !== prevOptions.enabled || nextRefetchInterval !== __privateGet(this, _currentRefetchInterval))) {
__privateMethod(this, _updateRefetchInterval, updateRefetchInterval_fn).call(this, nextRefetchInterval);
}
}
getOptimisticResult(options) {
const query = __privateGet(this, _client).getQueryCache().build(__privateGet(this, _client), options);
const result = this.createResult(query, options);
if (shouldAssignObserverCurrentProperties(this, result)) {
__privateSet(this, _currentResult, result);
__privateSet(this, _currentResultOptions, this.options);
__privateSet(this, _currentResultState, __privateGet(this, _currentQuery).state);
}
return result;
}
getCurrentResult() {
return __privateGet(this, _currentResult);
}
trackResult(result) {
const trackedResult = {};
Object.keys(result).forEach((key) => {
Object.defineProperty(trackedResult, key, {
configurable: false,
enumerable: true,
get: () => {
__privateGet(this, _trackedProps).add(key);
return result[key];
}
});
});
return trackedResult;
}
getCurrentQuery() {
return __privateGet(this, _currentQuery);
}
refetch({ ...options } = {}) {
return this.fetch({
...options
});
}
fetchOptimistic(options) {
const defaultedOptions = __privateGet(this, _client).defaultQueryOptions(options);
const query = __privateGet(this, _client).getQueryCache().build(__privateGet(this, _client), defaultedOptions);
query.isFetchingOptimistic = true;
return query.fetch().then(() => this.createResult(query, defaultedOptions));
}
fetch(fetchOptions) {
return __privateMethod(this, _executeFetch, executeFetch_fn).call(this, {
...fetchOptions,
cancelRefetch: fetchOptions.cancelRefetch ?? true
}).then(() => {
this.updateResult();
return __privateGet(this, _currentResult);
});
}
createResult(query, options) {
var _a;
const prevQuery = __privateGet(this, _currentQuery);
const prevOptions = this.options;
const prevResult = __privateGet(this, _currentResult);
const prevResultState = __privateGet(this, _currentResultState);
const prevResultOptions = __privateGet(this, _currentResultOptions);
const queryChange = query !== prevQuery;
const queryInitialState = queryChange ? query.state : __privateGet(this, _currentQueryInitialState);
const { state } = query;
let { error, errorUpdatedAt, fetchStatus, status } = state;
let isPlaceholderData = false;
let data;
if (options._optimisticResults) {
const mounted = this.hasListeners();
const fetchOnMount = !mounted && shouldFetchOnMount(query, options);
const fetchOptionally = mounted && shouldFetchOptionally(query, prevQuery, options, prevOptions);
if (fetchOnMount || fetchOptionally) {
fetchStatus = (0, import_retryer.canFetch)(query.options.networkMode) ? "fetching" : "paused";
if (!state.dataUpdatedAt) {
status = "pending";
}
}
if (options._optimisticResults === "isRestoring") {
fetchStatus = "idle";
}
}
if (options.select && typeof state.data !== "undefined") {
if (prevResult && state.data === (prevResultState == null ? void 0 : prevResultState.data) && options.select === __privateGet(this, _selectFn)) {
data = __privateGet(this, _selectResult);
} else {
try {
__privateSet(this, _selectFn, options.select);
data = options.select(state.data);
data = (0, import_utils.replaceData)(prevResult == null ? void 0 : prevResult.data, data, options);
__privateSet(this, _selectResult, data);
__privateSet(this, _selectError, null);
} catch (selectError) {
__privateSet(this, _selectError, selectError);
}
}
} else {
data = state.data;
}
if (typeof options.placeholderData !== "undefined" && typeof data === "undefined" && status === "pending") {
let placeholderData;
if ((prevResult == null ? void 0 : prevResult.isPlaceholderData) && options.placeholderData === (prevResultOptions == null ? void 0 : prevResultOptions.placeholderData)) {
placeholderData = prevResult.data;
} else {
placeholderData = typeof options.placeholderData === "function" ? options.placeholderData(
(_a = __privateGet(this, _lastQueryWithDefinedData)) == null ? void 0 : _a.state.data,
__privateGet(this, _lastQueryWithDefinedData)
) : options.placeholderData;
if (options.select && typeof placeholderData !== "undefined") {
try {
placeholderData = options.select(placeholderData);
__privateSet(this, _selectError, null);
} catch (selectError) {
__privateSet(this, _selectError, selectError);
}
}
}
if (typeof placeholderData !== "undefined") {
status = "success";
data = (0, import_utils.replaceData)(
prevResult == null ? void 0 : prevResult.data,
placeholderData,
options
);
isPlaceholderData = true;
}
}
if (__privateGet(this, _selectError)) {
error = __privateGet(this, _selectError);
data = __privateGet(this, _selectResult);
errorUpdatedAt = Date.now();
status = "error";
}
const isFetching = fetchStatus === "fetching";
const isPending = status === "pending";
const isError = status === "error";
const isLoading = isPending && isFetching;
const result = {
status,
fetchStatus,
isPending,
isSuccess: status === "success",
isError,
isInitialLoading: isLoading,
isLoading,
data,
dataUpdatedAt: state.dataUpdatedAt,
error,
errorUpdatedAt,
failureCount: state.fetchFailureCount,
failureReason: state.fetchFailureReason,
errorUpdateCount: state.errorUpdateCount,
isFetched: state.dataUpdateCount > 0 || state.errorUpdateCount > 0,
isFetchedAfterMount: state.dataUpdateCount > queryInitialState.dataUpdateCount || state.errorUpdateCount > queryInitialState.errorUpdateCount,
isFetching,
isRefetching: isFetching && !isPending,
isLoadingError: isError && state.dataUpdatedAt === 0,
isPaused: fetchStatus === "paused",
isPlaceholderData,
isRefetchError: isError && state.dataUpdatedAt !== 0,
isStale: isStale(query, options),
refetch: this.refetch
};
return result;
}
updateResult(notifyOptions) {
const prevResult = __privateGet(this, _currentResult);
const nextResult = this.createResult(__privateGet(this, _currentQuery), this.options);
__privateSet(this, _currentResultState, __privateGet(this, _currentQuery).state);
__privateSet(this, _currentResultOptions, this.options);
if ((0, import_utils.shallowEqualObjects)(nextResult, prevResult)) {
return;
}
if (__privateGet(this, _currentResultState).data !== void 0) {
__privateSet(this, _lastQueryWithDefinedData, __privateGet(this, _currentQuery));
}
__privateSet(this, _currentResult, nextResult);
const defaultNotifyOptions = {};
const shouldNotifyListeners = () => {
if (!prevResult) {
return true;
}
const { notifyOnChangeProps } = this.options;
const notifyOnChangePropsValue = typeof notifyOnChangeProps === "function" ? notifyOnChangeProps() : notifyOnChangeProps;
if (notifyOnChangePropsValue === "all" || !notifyOnChangePropsValue && !__privateGet(this, _trackedProps).size) {
return true;
}
const includedProps = new Set(
notifyOnChangePropsValue ?? __privateGet(this, _trackedProps)
);
if (this.options.throwOnError) {
includedProps.add("error");
}
return Object.keys(__privateGet(this, _currentResult)).some((key) => {
const typedKey = key;
const changed = __privateGet(this, _currentResult)[typedKey] !== prevResult[typedKey];
return changed && includedProps.has(typedKey);
});
};
if ((notifyOptions == null ? void 0 : notifyOptions.listeners) !== false && shouldNotifyListeners()) {
defaultNotifyOptions.listeners = true;
}
__privateMethod(this, _notify, notify_fn).call(this, { ...defaultNotifyOptions, ...notifyOptions });
}
onQueryUpdate() {
this.updateResult();
if (this.hasListeners()) {
__privateMethod(this, _updateTimers, updateTimers_fn).call(this);
}
}
};
_client = new WeakMap();
_currentQuery = new WeakMap();
_currentQueryInitialState = new WeakMap();
_currentResult = new WeakMap();
_currentResultState = new WeakMap();
_currentResultOptions = new WeakMap();
_selectError = new WeakMap();
_selectFn = new WeakMap();
_selectResult = new WeakMap();
_lastQueryWithDefinedData = new WeakMap();
_staleTimeoutId = new WeakMap();
_refetchIntervalId = new WeakMap();
_currentRefetchInterval = new WeakMap();
_trackedProps = new WeakMap();
_executeFetch = new WeakSet();
executeFetch_fn = function(fetchOptions) {
__privateMethod(this, _updateQuery, updateQuery_fn).call(this);
let promise = __privateGet(this, _currentQuery).fetch(
this.options,
fetchOptions
);
if (!(fetchOptions == null ? void 0 : fetchOptions.throwOnError)) {
promise = promise.catch(import_utils.noop);
}
return promise;
};
_updateStaleTimeout = new WeakSet();
updateStaleTimeout_fn = function() {
__privateMethod(this, _clearStaleTimeout, clearStaleTimeout_fn).call(this);
if (import_utils.isServer || __privateGet(this, _currentResult).isStale || !(0, import_utils.isValidTimeout)(this.options.staleTime)) {
return;
}
const time = (0, import_utils.timeUntilStale)(
__privateGet(this, _currentResult).dataUpdatedAt,
this.options.staleTime
);
const timeout = time + 1;
__privateSet(this, _staleTimeoutId, setTimeout(() => {
if (!__privateGet(this, _currentResult).isStale) {
this.updateResult();
}
}, timeout));
};
_computeRefetchInterval = new WeakSet();
computeRefetchInterval_fn = function() {
return (typeof this.options.refetchInterval === "function" ? this.options.refetchInterval(__privateGet(this, _currentQuery)) : this.options.refetchInterval) ?? false;
};
_updateRefetchInterval = new WeakSet();
updateRefetchInterval_fn = function(nextInterval) {
__privateMethod(this, _clearRefetchInterval, clearRefetchInterval_fn).call(this);
__privateSet(this, _currentRefetchInterval, nextInterval);
if (import_utils.isServer || this.options.enabled === false || !(0, import_utils.isValidTimeout)(__privateGet(this, _currentRefetchInterval)) || __privateGet(this, _currentRefetchInterval) === 0) {
return;
}
__privateSet(this, _refetchIntervalId, setInterval(() => {
if (this.options.refetchIntervalInBackground || import_focusManager.focusManager.isFocused()) {
__privateMethod(this, _executeFetch, executeFetch_fn).call(this);
}
}, __privateGet(this, _currentRefetchInterval)));
};
_updateTimers = new WeakSet();
updateTimers_fn = function() {
__privateMethod(this, _updateStaleTimeout, updateStaleTimeout_fn).call(this);
__privateMethod(this, _updateRefetchInterval, updateRefetchInterval_fn).call(this, __privateMethod(this, _computeRefetchInterval, computeRefetchInterval_fn).call(this));
};
_clearStaleTimeout = new WeakSet();
clearStaleTimeout_fn = function() {
if (__privateGet(this, _staleTimeoutId)) {
clearTimeout(__privateGet(this, _staleTimeoutId));
__privateSet(this, _staleTimeoutId, void 0);
}
};
_clearRefetchInterval = new WeakSet();
clearRefetchInterval_fn = function() {
if (__privateGet(this, _refetchIntervalId)) {
clearInterval(__privateGet(this, _refetchIntervalId));
__privateSet(this, _refetchIntervalId, void 0);
}
};
_updateQuery = new WeakSet();
updateQuery_fn = function() {
const query = __privateGet(this, _client).getQueryCache().build(__privateGet(this, _client), this.options);
if (query === __privateGet(this, _currentQuery)) {
return;
}
const prevQuery = __privateGet(this, _currentQuery);
__privateSet(this, _currentQuery, query);
__privateSet(this, _currentQueryInitialState, query.state);
if (this.hasListeners()) {
prevQuery == null ? void 0 : prevQuery.removeObserver(this);
query.addObserver(this);
}
};
_notify = new WeakSet();
notify_fn = function(notifyOptions) {
import_notifyManager.notifyManager.batch(() => {
if (notifyOptions.listeners) {
this.listeners.forEach((listener) => {
listener(__privateGet(this, _currentResult));
});
}
__privateGet(this, _client).getQueryCache().notify({
query: __privateGet(this, _currentQuery),
type: "observerResultsUpdated"
});
});
};
function shouldLoadOnMount(query, options) {
return options.enabled !== false && !query.state.dataUpdatedAt && !(query.state.status === "error" && options.retryOnMount === false);
}
function shouldFetchOnMount(query, options) {
return shouldLoadOnMount(query, options) || query.state.dataUpdatedAt > 0 && shouldFetchOn(query, options, options.refetchOnMount);
}
function shouldFetchOn(query, options, field) {
if (options.enabled !== false) {
const value = typeof field === "function" ? field(query) : field;
return value === "always" || value !== false && isStale(query, options);
}
return false;
}
function shouldFetchOptionally(query, prevQuery, options, prevOptions) {
return options.enabled !== false && (query !== prevQuery || prevOptions.enabled === false) && (!options.suspense || query.state.status !== "error") && isStale(query, options);
}
function isStale(query, options) {
return query.isStaleByTime(options.staleTime);
}
function shouldAssignObserverCurrentProperties(observer, optimisticResult) {
if (!(0, import_utils.shallowEqualObjects)(observer.getCurrentResult(), optimisticResult)) {
return true;
}
return false;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
QueryObserver
});
//# sourceMappingURL=queryObserver.cjs.map