UNPKG

14 kBJavaScriptView Raw
1import { __assign, __rest } from "tslib";
2import { invariant } from "../../utilities/globals/index.js";
3import { useCallback, useContext, useMemo, useRef, useState, } from 'react';
4import { useSyncExternalStore } from "./useSyncExternalStore.js";
5import { equal } from '@wry/equality';
6import { mergeOptions } from "../../core/index.js";
7import { getApolloContext } from "../context/index.js";
8import { ApolloError } from "../../errors/index.js";
9import { NetworkStatus, } from "../../core/index.js";
10import { DocumentType, verifyDocumentType } from "../parser/index.js";
11import { useApolloClient } from "./useApolloClient.js";
12import { canUseWeakMap, canUseWeakSet, compact, isNonEmptyArray, maybeDeepFreeze } from "../../utilities/index.js";
13var hasOwnProperty = Object.prototype.hasOwnProperty;
14export function useQuery(query, options) {
15 if (options === void 0) { options = Object.create(null); }
16 return useInternalState(useApolloClient(options.client), query).useQuery(options);
17}
18export function useInternalState(client, query) {
19 var stateRef = useRef();
20 if (!stateRef.current ||
21 client !== stateRef.current.client ||
22 query !== stateRef.current.query) {
23 stateRef.current = new InternalState(client, query, stateRef.current);
24 }
25 var state = stateRef.current;
26 var _a = useState(0), _tick = _a[0], setTick = _a[1];
27 state.forceUpdate = function () {
28 setTick(function (tick) { return tick + 1; });
29 };
30 return state;
31}
32var InternalState = (function () {
33 function InternalState(client, query, previous) {
34 this.client = client;
35 this.query = query;
36 this.asyncResolveFns = new Set();
37 this.optionsToIgnoreOnce = new (canUseWeakSet ? WeakSet : Set)();
38 this.ssrDisabledResult = maybeDeepFreeze({
39 loading: true,
40 data: void 0,
41 error: void 0,
42 networkStatus: NetworkStatus.loading,
43 });
44 this.skipStandbyResult = maybeDeepFreeze({
45 loading: false,
46 data: void 0,
47 error: void 0,
48 networkStatus: NetworkStatus.ready,
49 });
50 this.toQueryResultCache = new (canUseWeakMap ? WeakMap : Map)();
51 verifyDocumentType(query, DocumentType.Query);
52 var previousResult = previous && previous.result;
53 var previousData = previousResult && previousResult.data;
54 if (previousData) {
55 this.previousData = previousData;
56 }
57 }
58 InternalState.prototype.forceUpdate = function () {
59 __DEV__ && invariant.warn("Calling default no-op implementation of InternalState#forceUpdate");
60 };
61 InternalState.prototype.asyncUpdate = function (signal) {
62 var _this = this;
63 return new Promise(function (resolve, reject) {
64 var watchQueryOptions = _this.watchQueryOptions;
65 var handleAborted = function () {
66 _this.asyncResolveFns.delete(resolve);
67 _this.optionsToIgnoreOnce.delete(watchQueryOptions);
68 signal.removeEventListener('abort', handleAborted);
69 reject(signal.reason);
70 };
71 _this.asyncResolveFns.add(resolve);
72 _this.optionsToIgnoreOnce.add(watchQueryOptions);
73 signal.addEventListener('abort', handleAborted);
74 _this.forceUpdate();
75 });
76 };
77 InternalState.prototype.useQuery = function (options) {
78 var _this = this;
79 this.renderPromises = useContext(getApolloContext()).renderPromises;
80 this.useOptions(options);
81 var obsQuery = this.useObservableQuery();
82 var result = useSyncExternalStore(useCallback(function () {
83 if (_this.renderPromises) {
84 return function () { };
85 }
86 var onNext = function () {
87 var previousResult = _this.result;
88 var result = obsQuery.getCurrentResult();
89 if (previousResult &&
90 previousResult.loading === result.loading &&
91 previousResult.networkStatus === result.networkStatus &&
92 equal(previousResult.data, result.data)) {
93 return;
94 }
95 _this.setResult(result);
96 };
97 var onError = function (error) {
98 var last = obsQuery["last"];
99 subscription.unsubscribe();
100 try {
101 obsQuery.resetLastResults();
102 subscription = obsQuery.subscribe(onNext, onError);
103 }
104 finally {
105 obsQuery["last"] = last;
106 }
107 if (!hasOwnProperty.call(error, 'graphQLErrors')) {
108 throw error;
109 }
110 var previousResult = _this.result;
111 if (!previousResult ||
112 (previousResult && previousResult.loading) ||
113 !equal(error, previousResult.error)) {
114 _this.setResult({
115 data: (previousResult && previousResult.data),
116 error: error,
117 loading: false,
118 networkStatus: NetworkStatus.error,
119 });
120 }
121 };
122 var subscription = obsQuery.subscribe(onNext, onError);
123 return function () { return subscription.unsubscribe(); };
124 }, [
125 obsQuery,
126 this.renderPromises,
127 this.client.disableNetworkFetches,
128 ]), function () { return _this.getCurrentResult(); }, function () { return _this.getCurrentResult(); });
129 this.unsafeHandlePartialRefetch(result);
130 var queryResult = this.toQueryResult(result);
131 if (!queryResult.loading && this.asyncResolveFns.size) {
132 this.asyncResolveFns.forEach(function (resolve) { return resolve(queryResult); });
133 this.asyncResolveFns.clear();
134 }
135 return queryResult;
136 };
137 InternalState.prototype.useOptions = function (options) {
138 var _a;
139 var watchQueryOptions = this.createWatchQueryOptions(this.queryHookOptions = options);
140 var currentWatchQueryOptions = this.watchQueryOptions;
141 if (this.optionsToIgnoreOnce.has(currentWatchQueryOptions) ||
142 !equal(watchQueryOptions, currentWatchQueryOptions)) {
143 this.watchQueryOptions = watchQueryOptions;
144 if (currentWatchQueryOptions && this.observable) {
145 this.optionsToIgnoreOnce.delete(currentWatchQueryOptions);
146 this.observable.reobserve(this.getObsQueryOptions());
147 this.previousData = ((_a = this.result) === null || _a === void 0 ? void 0 : _a.data) || this.previousData;
148 this.result = void 0;
149 }
150 }
151 this.onCompleted = options.onCompleted || InternalState.prototype.onCompleted;
152 this.onError = options.onError || InternalState.prototype.onError;
153 if ((this.renderPromises || this.client.disableNetworkFetches) &&
154 this.queryHookOptions.ssr === false &&
155 !this.queryHookOptions.skip) {
156 this.result = this.ssrDisabledResult;
157 }
158 else if (this.queryHookOptions.skip ||
159 this.watchQueryOptions.fetchPolicy === 'standby') {
160 this.result = this.skipStandbyResult;
161 }
162 else if (this.result === this.ssrDisabledResult ||
163 this.result === this.skipStandbyResult) {
164 this.result = void 0;
165 }
166 };
167 InternalState.prototype.getObsQueryOptions = function () {
168 var toMerge = [];
169 var globalDefaults = this.client.defaultOptions.watchQuery;
170 if (globalDefaults)
171 toMerge.push(globalDefaults);
172 if (this.queryHookOptions.defaultOptions) {
173 toMerge.push(this.queryHookOptions.defaultOptions);
174 }
175 toMerge.push(compact(this.observable && this.observable.options, this.watchQueryOptions));
176 return toMerge.reduce(mergeOptions);
177 };
178 InternalState.prototype.createWatchQueryOptions = function (_a) {
179 var _b;
180 if (_a === void 0) { _a = {}; }
181 var skip = _a.skip, ssr = _a.ssr, onCompleted = _a.onCompleted, onError = _a.onError, defaultOptions = _a.defaultOptions, otherOptions = __rest(_a, ["skip", "ssr", "onCompleted", "onError", "defaultOptions"]);
182 var watchQueryOptions = Object.assign(otherOptions, { query: this.query });
183 if (this.renderPromises &&
184 (watchQueryOptions.fetchPolicy === 'network-only' ||
185 watchQueryOptions.fetchPolicy === 'cache-and-network')) {
186 watchQueryOptions.fetchPolicy = 'cache-first';
187 }
188 if (!watchQueryOptions.variables) {
189 watchQueryOptions.variables = {};
190 }
191 if (skip) {
192 var _c = watchQueryOptions.fetchPolicy, fetchPolicy = _c === void 0 ? this.getDefaultFetchPolicy() : _c, _d = watchQueryOptions.initialFetchPolicy, initialFetchPolicy = _d === void 0 ? fetchPolicy : _d;
193 Object.assign(watchQueryOptions, {
194 initialFetchPolicy: initialFetchPolicy,
195 fetchPolicy: 'standby',
196 });
197 }
198 else if (!watchQueryOptions.fetchPolicy) {
199 watchQueryOptions.fetchPolicy =
200 ((_b = this.observable) === null || _b === void 0 ? void 0 : _b.options.initialFetchPolicy) ||
201 this.getDefaultFetchPolicy();
202 }
203 return watchQueryOptions;
204 };
205 InternalState.prototype.getDefaultFetchPolicy = function () {
206 var _a, _b;
207 return (((_a = this.queryHookOptions.defaultOptions) === null || _a === void 0 ? void 0 : _a.fetchPolicy) ||
208 ((_b = this.client.defaultOptions.watchQuery) === null || _b === void 0 ? void 0 : _b.fetchPolicy) ||
209 "cache-first");
210 };
211 InternalState.prototype.onCompleted = function (data) { };
212 InternalState.prototype.onError = function (error) { };
213 InternalState.prototype.useObservableQuery = function () {
214 var obsQuery = this.observable =
215 this.renderPromises
216 && this.renderPromises.getSSRObservable(this.watchQueryOptions)
217 || this.observable
218 || this.client.watchQuery(this.getObsQueryOptions());
219 this.obsQueryFields = useMemo(function () { return ({
220 refetch: obsQuery.refetch.bind(obsQuery),
221 reobserve: obsQuery.reobserve.bind(obsQuery),
222 fetchMore: obsQuery.fetchMore.bind(obsQuery),
223 updateQuery: obsQuery.updateQuery.bind(obsQuery),
224 startPolling: obsQuery.startPolling.bind(obsQuery),
225 stopPolling: obsQuery.stopPolling.bind(obsQuery),
226 subscribeToMore: obsQuery.subscribeToMore.bind(obsQuery),
227 }); }, [obsQuery]);
228 var ssrAllowed = !(this.queryHookOptions.ssr === false ||
229 this.queryHookOptions.skip);
230 if (this.renderPromises && ssrAllowed) {
231 this.renderPromises.registerSSRObservable(obsQuery);
232 if (obsQuery.getCurrentResult().loading) {
233 this.renderPromises.addObservableQueryPromise(obsQuery);
234 }
235 }
236 return obsQuery;
237 };
238 InternalState.prototype.setResult = function (nextResult) {
239 var previousResult = this.result;
240 if (previousResult && previousResult.data) {
241 this.previousData = previousResult.data;
242 }
243 this.result = nextResult;
244 this.forceUpdate();
245 this.handleErrorOrCompleted(nextResult);
246 };
247 InternalState.prototype.handleErrorOrCompleted = function (result) {
248 var _this = this;
249 if (!result.loading) {
250 var error_1 = this.toApolloError(result);
251 Promise.resolve().then(function () {
252 if (error_1) {
253 _this.onError(error_1);
254 }
255 else if (result.data) {
256 _this.onCompleted(result.data);
257 }
258 }).catch(function (error) {
259 __DEV__ && invariant.warn(error);
260 });
261 }
262 };
263 InternalState.prototype.toApolloError = function (result) {
264 return isNonEmptyArray(result.errors)
265 ? new ApolloError({ graphQLErrors: result.errors })
266 : result.error;
267 };
268 InternalState.prototype.getCurrentResult = function () {
269 if (!this.result) {
270 this.handleErrorOrCompleted(this.result = this.observable.getCurrentResult());
271 }
272 return this.result;
273 };
274 InternalState.prototype.toQueryResult = function (result) {
275 var queryResult = this.toQueryResultCache.get(result);
276 if (queryResult)
277 return queryResult;
278 var data = result.data, partial = result.partial, resultWithoutPartial = __rest(result, ["data", "partial"]);
279 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 }));
280 if (!queryResult.error && isNonEmptyArray(result.errors)) {
281 queryResult.error = new ApolloError({ graphQLErrors: result.errors });
282 }
283 return queryResult;
284 };
285 InternalState.prototype.unsafeHandlePartialRefetch = function (result) {
286 if (result.partial &&
287 this.queryHookOptions.partialRefetch &&
288 !result.loading &&
289 (!result.data || Object.keys(result.data).length === 0) &&
290 this.observable.options.fetchPolicy !== 'cache-only') {
291 Object.assign(result, {
292 loading: true,
293 networkStatus: NetworkStatus.refetch,
294 });
295 this.observable.refetch();
296 }
297 };
298 return InternalState;
299}());
300//# sourceMappingURL=useQuery.js.map
\No newline at end of file