@apollo/client
Version:
A fully-featured caching GraphQL client.
300 lines • 14 kB
JavaScript
import { __assign, __rest } from "tslib";
import { invariant } from "../../utilities/globals/index.js";
import { useCallback, useContext, useMemo, useRef, useState, } from 'react';
import { useSyncExternalStore } from "./useSyncExternalStore.js";
import { equal } from '@wry/equality';
import { mergeOptions } from "../../core/index.js";
import { getApolloContext } from "../context/index.js";
import { ApolloError } from "../../errors/index.js";
import { NetworkStatus, } from "../../core/index.js";
import { DocumentType, verifyDocumentType } from "../parser/index.js";
import { useApolloClient } from "./useApolloClient.js";
import { canUseWeakMap, canUseWeakSet, compact, isNonEmptyArray, maybeDeepFreeze } from "../../utilities/index.js";
var hasOwnProperty = Object.prototype.hasOwnProperty;
export function useQuery(query, options) {
if (options === void 0) { options = Object.create(null); }
return useInternalState(useApolloClient(options.client), query).useQuery(options);
}
export function useInternalState(client, query) {
var stateRef = useRef();
if (!stateRef.current ||
client !== stateRef.current.client ||
query !== stateRef.current.query) {
stateRef.current = new InternalState(client, query, stateRef.current);
}
var state = stateRef.current;
var _a = useState(0), _tick = _a[0], setTick = _a[1];
state.forceUpdate = function () {
setTick(function (tick) { return tick + 1; });
};
return state;
}
var InternalState = (function () {
function InternalState(client, query, previous) {
this.client = client;
this.query = query;
this.asyncResolveFns = new Set();
this.optionsToIgnoreOnce = new (canUseWeakSet ? WeakSet : Set)();
this.ssrDisabledResult = maybeDeepFreeze({
loading: true,
data: void 0,
error: void 0,
networkStatus: NetworkStatus.loading,
});
this.skipStandbyResult = maybeDeepFreeze({
loading: false,
data: void 0,
error: void 0,
networkStatus: NetworkStatus.ready,
});
this.toQueryResultCache = new (canUseWeakMap ? WeakMap : Map)();
verifyDocumentType(query, DocumentType.Query);
var previousResult = previous && previous.result;
var previousData = previousResult && previousResult.data;
if (previousData) {
this.previousData = previousData;
}
}
InternalState.prototype.forceUpdate = function () {
__DEV__ && invariant.warn("Calling default no-op implementation of InternalState#forceUpdate");
};
InternalState.prototype.asyncUpdate = function (signal) {
var _this = this;
return new Promise(function (resolve, reject) {
var watchQueryOptions = _this.watchQueryOptions;
var handleAborted = function () {
_this.asyncResolveFns.delete(resolve);
_this.optionsToIgnoreOnce.delete(watchQueryOptions);
signal.removeEventListener('abort', handleAborted);
reject(signal.reason);
};
_this.asyncResolveFns.add(resolve);
_this.optionsToIgnoreOnce.add(watchQueryOptions);
signal.addEventListener('abort', handleAborted);
_this.forceUpdate();
});
};
InternalState.prototype.useQuery = function (options) {
var _this = this;
this.renderPromises = useContext(getApolloContext()).renderPromises;
this.useOptions(options);
var obsQuery = this.useObservableQuery();
var result = useSyncExternalStore(useCallback(function () {
if (_this.renderPromises) {
return function () { };
}
var onNext = function () {
var previousResult = _this.result;
var result = obsQuery.getCurrentResult();
if (previousResult &&
previousResult.loading === result.loading &&
previousResult.networkStatus === result.networkStatus &&
equal(previousResult.data, result.data)) {
return;
}
_this.setResult(result);
};
var onError = function (error) {
var last = obsQuery["last"];
subscription.unsubscribe();
try {
obsQuery.resetLastResults();
subscription = obsQuery.subscribe(onNext, onError);
}
finally {
obsQuery["last"] = last;
}
if (!hasOwnProperty.call(error, 'graphQLErrors')) {
throw error;
}
var previousResult = _this.result;
if (!previousResult ||
(previousResult && previousResult.loading) ||
!equal(error, previousResult.error)) {
_this.setResult({
data: (previousResult && previousResult.data),
error: error,
loading: false,
networkStatus: NetworkStatus.error,
});
}
};
var subscription = obsQuery.subscribe(onNext, onError);
return function () { return subscription.unsubscribe(); };
}, [
obsQuery,
this.renderPromises,
this.client.disableNetworkFetches,
]), function () { return _this.getCurrentResult(); }, function () { return _this.getCurrentResult(); });
this.unsafeHandlePartialRefetch(result);
var queryResult = this.toQueryResult(result);
if (!queryResult.loading && this.asyncResolveFns.size) {
this.asyncResolveFns.forEach(function (resolve) { return resolve(queryResult); });
this.asyncResolveFns.clear();
}
return queryResult;
};
InternalState.prototype.useOptions = function (options) {
var _a;
var watchQueryOptions = this.createWatchQueryOptions(this.queryHookOptions = options);
var currentWatchQueryOptions = this.watchQueryOptions;
if (this.optionsToIgnoreOnce.has(currentWatchQueryOptions) ||
!equal(watchQueryOptions, currentWatchQueryOptions)) {
this.watchQueryOptions = watchQueryOptions;
if (currentWatchQueryOptions && this.observable) {
this.optionsToIgnoreOnce.delete(currentWatchQueryOptions);
this.observable.reobserve(this.getObsQueryOptions());
this.previousData = ((_a = this.result) === null || _a === void 0 ? void 0 : _a.data) || this.previousData;
this.result = void 0;
}
}
this.onCompleted = options.onCompleted || InternalState.prototype.onCompleted;
this.onError = options.onError || InternalState.prototype.onError;
if ((this.renderPromises || this.client.disableNetworkFetches) &&
this.queryHookOptions.ssr === false &&
!this.queryHookOptions.skip) {
this.result = this.ssrDisabledResult;
}
else if (this.queryHookOptions.skip ||
this.watchQueryOptions.fetchPolicy === 'standby') {
this.result = this.skipStandbyResult;
}
else if (this.result === this.ssrDisabledResult ||
this.result === this.skipStandbyResult) {
this.result = void 0;
}
};
InternalState.prototype.getObsQueryOptions = function () {
var toMerge = [];
var globalDefaults = this.client.defaultOptions.watchQuery;
if (globalDefaults)
toMerge.push(globalDefaults);
if (this.queryHookOptions.defaultOptions) {
toMerge.push(this.queryHookOptions.defaultOptions);
}
toMerge.push(compact(this.observable && this.observable.options, this.watchQueryOptions));
return toMerge.reduce(mergeOptions);
};
InternalState.prototype.createWatchQueryOptions = function (_a) {
var _b;
if (_a === void 0) { _a = {}; }
var skip = _a.skip, ssr = _a.ssr, onCompleted = _a.onCompleted, onError = _a.onError, defaultOptions = _a.defaultOptions, otherOptions = __rest(_a, ["skip", "ssr", "onCompleted", "onError", "defaultOptions"]);
var watchQueryOptions = Object.assign(otherOptions, { query: this.query });
if (this.renderPromises &&
(watchQueryOptions.fetchPolicy === 'network-only' ||
watchQueryOptions.fetchPolicy === 'cache-and-network')) {
watchQueryOptions.fetchPolicy = 'cache-first';
}
if (!watchQueryOptions.variables) {
watchQueryOptions.variables = {};
}
if (skip) {
var _c = watchQueryOptions.fetchPolicy, fetchPolicy = _c === void 0 ? this.getDefaultFetchPolicy() : _c, _d = watchQueryOptions.initialFetchPolicy, initialFetchPolicy = _d === void 0 ? fetchPolicy : _d;
Object.assign(watchQueryOptions, {
initialFetchPolicy: initialFetchPolicy,
fetchPolicy: 'standby',
});
}
else if (!watchQueryOptions.fetchPolicy) {
watchQueryOptions.fetchPolicy =
((_b = this.observable) === null || _b === void 0 ? void 0 : _b.options.initialFetchPolicy) ||
this.getDefaultFetchPolicy();
}
return watchQueryOptions;
};
InternalState.prototype.getDefaultFetchPolicy = function () {
var _a, _b;
return (((_a = this.queryHookOptions.defaultOptions) === null || _a === void 0 ? void 0 : _a.fetchPolicy) ||
((_b = this.client.defaultOptions.watchQuery) === null || _b === void 0 ? void 0 : _b.fetchPolicy) ||
"cache-first");
};
InternalState.prototype.onCompleted = function (data) { };
InternalState.prototype.onError = function (error) { };
InternalState.prototype.useObservableQuery = function () {
var obsQuery = this.observable =
this.renderPromises
&& this.renderPromises.getSSRObservable(this.watchQueryOptions)
|| this.observable
|| this.client.watchQuery(this.getObsQueryOptions());
this.obsQueryFields = useMemo(function () { return ({
refetch: obsQuery.refetch.bind(obsQuery),
reobserve: obsQuery.reobserve.bind(obsQuery),
fetchMore: obsQuery.fetchMore.bind(obsQuery),
updateQuery: obsQuery.updateQuery.bind(obsQuery),
startPolling: obsQuery.startPolling.bind(obsQuery),
stopPolling: obsQuery.stopPolling.bind(obsQuery),
subscribeToMore: obsQuery.subscribeToMore.bind(obsQuery),
}); }, [obsQuery]);
var ssrAllowed = !(this.queryHookOptions.ssr === false ||
this.queryHookOptions.skip);
if (this.renderPromises && ssrAllowed) {
this.renderPromises.registerSSRObservable(obsQuery);
if (obsQuery.getCurrentResult().loading) {
this.renderPromises.addObservableQueryPromise(obsQuery);
}
}
return obsQuery;
};
InternalState.prototype.setResult = function (nextResult) {
var previousResult = this.result;
if (previousResult && previousResult.data) {
this.previousData = previousResult.data;
}
this.result = nextResult;
this.forceUpdate();
this.handleErrorOrCompleted(nextResult);
};
InternalState.prototype.handleErrorOrCompleted = function (result) {
var _this = this;
if (!result.loading) {
var error_1 = this.toApolloError(result);
Promise.resolve().then(function () {
if (error_1) {
_this.onError(error_1);
}
else if (result.data) {
_this.onCompleted(result.data);
}
}).catch(function (error) {
__DEV__ && invariant.warn(error);
});
}
};
InternalState.prototype.toApolloError = function (result) {
return isNonEmptyArray(result.errors)
? new ApolloError({ graphQLErrors: result.errors })
: result.error;
};
InternalState.prototype.getCurrentResult = function () {
if (!this.result) {
this.handleErrorOrCompleted(this.result = this.observable.getCurrentResult());
}
return this.result;
};
InternalState.prototype.toQueryResult = function (result) {
var queryResult = this.toQueryResultCache.get(result);
if (queryResult)
return queryResult;
var data = result.data, partial = result.partial, resultWithoutPartial = __rest(result, ["data", "partial"]);
this.toQueryResultCache.set(result, queryResult = __assign(__assign(__assign({ data: data }, resultWithoutPartial), this.obsQueryFields), { client: this.client, observable: this.observable, variables: this.observable.variables, called: !this.queryHookOptions.skip, previousData: this.previousData }));
if (!queryResult.error && isNonEmptyArray(result.errors)) {
queryResult.error = new ApolloError({ graphQLErrors: result.errors });
}
return queryResult;
};
InternalState.prototype.unsafeHandlePartialRefetch = function (result) {
if (result.partial &&
this.queryHookOptions.partialRefetch &&
!result.loading &&
(!result.data || Object.keys(result.data).length === 0) &&
this.observable.options.fetchPolicy !== 'cache-only') {
Object.assign(result, {
loading: true,
networkStatus: NetworkStatus.refetch,
});
this.observable.refetch();
}
};
return InternalState;
}());
//# sourceMappingURL=useQuery.js.map