@apollo/client
Version:
A fully-featured caching GraphQL client.
82 lines • 3.67 kB
JavaScript
import { assertWrappedQueryRef, getWrappedPromise, InternalQueryReference, wrapQueryRef, } from "@apollo/client/react/internal";
import { FinalizationRegistry } from "@apollo/client/utilities/internal/ponyfills";
import { wrapHook } from "../hooks/internal/index.js";
/**
* A higher order function that returns a `preloadQuery` function which
* can be used to begin loading a query with the given `client`. This is useful
* when you want to start loading a query as early as possible outside of a
* React component.
*
* > Refer to the [Suspense - Initiating queries outside React](https://www.apollographql.com/docs/react/data/suspense#initiating-queries-outside-react) section for a more in-depth overview.
*
* @param client - The `ApolloClient` instance that will be used to load queries
* from the returned `preloadQuery` function.
* @returns The `preloadQuery` function.
*
* @example
*
* ```js
* const preloadQuery = createQueryPreloader(client);
* ```
*/
export function createQueryPreloader(client) {
return wrapHook("createQueryPreloader", _createQueryPreloader, client)(client);
}
const _createQueryPreloader = (client) => {
function preloadQuery(query, options = {}) {
const queryRef = new InternalQueryReference(client.watchQuery({
...options,
query,
notifyOnNetworkStatusChange: false,
}), {
autoDisposeTimeoutMs: client.defaultOptions.react?.suspense?.autoDisposeTimeoutMs,
});
const wrapped = wrapQueryRef(queryRef);
softRetainWhileReferenced(wrapped, queryRef);
return wrapped;
}
return Object.assign(preloadQuery, {
toPromise(queryRef) {
assertWrappedQueryRef(queryRef);
return getWrappedPromise(queryRef).then(() => queryRef);
},
});
};
/**
* Soft-retains the underlying `InternalQueryReference` while the `PreloadedQueryRef`
* is still reachable.
* When the `PreloadedQueryRef` is garbage collected, the soft retain is
* disposed of, but only after the initial query has finished loading.
* Once the `InternalQueryReference` is properly retained, the check for garbage
* collection is unregistered and the soft retain is disposed of immediately.
*/
// this is an individual function to avoid closing over any values more than necessary
function softRetainWhileReferenced(wrapped, queryRef) {
const { softDispose, delayedSoftDispose } = getCleanup(queryRef);
registry.register(wrapped, delayedSoftDispose, queryRef);
// This will unregister the cleanup from the finalization registry when
// the queryRef is properly retained.
// This is mostly done to keep the FinalizationRegistry from holding too many
// cleanup functions, as our React Native polyfill has to iterate all of them regularly.
queryRef.retain = unregisterOnRetain(queryRef.retain, softDispose);
}
// this is an individual function to avoid closing over any values more than necessary
function unregisterOnRetain(originalRetain, softDispose) {
return function (...args) {
registry.unregister(this);
const dispose = originalRetain.apply(this, args);
softDispose();
return dispose;
};
}
// this is an individual function to avoid closing over any values more than necessary
function getCleanup(queryRef) {
const softDispose = queryRef.softRetain();
const initialPromise = queryRef.promise;
return {
softDispose,
delayedSoftDispose: () => initialPromise.finally(softDispose).catch(() => { }),
};
}
const registry = new FinalizationRegistry((cleanup) => cleanup());
//# sourceMappingURL=createQueryPreloader.js.map