UNPKG

react-query

Version:

Hooks for managing, caching and syncing asynchronous and remote data in React

330 lines (284 loc) 10.7 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) : typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ReactQueryPersistQueryClient = {}, global.React)); })(this, (function (exports, React) { 'use strict'; function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var React__default = /*#__PURE__*/_interopDefaultLegacy(React); // TYPES // FUNCTIONS function dehydrateMutation(mutation) { return { mutationKey: mutation.options.mutationKey, state: mutation.state }; } // Most config is not dehydrated but instead meant to configure again when // consuming the de/rehydrated data, typically with useQuery on the client. // Sometimes it might make sense to prefetch data on the server and include // in the html-payload, but not consume it on the initial render. function dehydrateQuery(query) { return { state: query.state, queryKey: query.queryKey, queryHash: query.queryHash }; } function defaultShouldDehydrateMutation(mutation) { return mutation.state.isPaused; } function defaultShouldDehydrateQuery(query) { return query.state.status === 'success'; } function dehydrate(client, options = {}) { const mutations = []; const queries = []; if (options.dehydrateMutations !== false) { const shouldDehydrateMutation = options.shouldDehydrateMutation || defaultShouldDehydrateMutation; client.getMutationCache().getAll().forEach(mutation => { if (shouldDehydrateMutation(mutation)) { mutations.push(dehydrateMutation(mutation)); } }); } if (options.dehydrateQueries !== false) { const shouldDehydrateQuery = options.shouldDehydrateQuery || defaultShouldDehydrateQuery; client.getQueryCache().getAll().forEach(query => { if (shouldDehydrateQuery(query)) { queries.push(dehydrateQuery(query)); } }); } return { mutations, queries }; } function hydrate(client, dehydratedState, options) { if (typeof dehydratedState !== 'object' || dehydratedState === null) { return; } const mutationCache = client.getMutationCache(); const queryCache = client.getQueryCache(); // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition const mutations = dehydratedState.mutations || []; // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition const queries = dehydratedState.queries || []; mutations.forEach(dehydratedMutation => { var _options$defaultOptio; mutationCache.build(client, { ...(options == null ? void 0 : (_options$defaultOptio = options.defaultOptions) == null ? void 0 : _options$defaultOptio.mutations), mutationKey: dehydratedMutation.mutationKey }, dehydratedMutation.state); }); queries.forEach(dehydratedQuery => { var _options$defaultOptio2; const query = queryCache.get(dehydratedQuery.queryHash); // Do not hydrate if an existing query exists with newer data if (query) { if (query.state.dataUpdatedAt < dehydratedQuery.state.dataUpdatedAt) { query.setState(dehydratedQuery.state); } return; } // Restore query queryCache.build(client, { ...(options == null ? void 0 : (_options$defaultOptio2 = options.defaultOptions) == null ? void 0 : _options$defaultOptio2.queries), queryKey: dehydratedQuery.queryKey, queryHash: dehydratedQuery.queryHash }, dehydratedQuery.state); }); } /** * Restores persisted data to the QueryCache * - data obtained from persister.restoreClient * - data is hydrated using hydrateOptions * If data is expired, busted, empty, or throws, it runs persister.removeClient */ async function persistQueryClientRestore({ queryClient, persister, maxAge = 1000 * 60 * 60 * 24, buster = '', hydrateOptions }) { if (typeof window !== 'undefined') { try { const persistedClient = await persister.restoreClient(); if (persistedClient) { if (persistedClient.timestamp) { const expired = Date.now() - persistedClient.timestamp > maxAge; const busted = persistedClient.buster !== buster; if (expired || busted) { persister.removeClient(); } else { hydrate(queryClient, persistedClient.clientState, hydrateOptions); } } else { persister.removeClient(); } } } catch (err) { if (process.env.NODE_ENV !== 'production') { queryClient.getLogger().error(err); queryClient.getLogger().warn('Encountered an error attempting to restore client cache from persisted location. As a precaution, the persisted cache will be discarded.'); } persister.removeClient(); } } } /** * Persists data from the QueryCache * - data dehydrated using dehydrateOptions * - data is persisted using persister.persistClient */ async function persistQueryClientSave({ queryClient, persister, buster = '', dehydrateOptions }) { if (typeof window !== 'undefined') { const persistClient = { buster, timestamp: Date.now(), clientState: dehydrate(queryClient, dehydrateOptions) }; await persister.persistClient(persistClient); } } /** * Subscribe to QueryCache and MutationCache updates (for persisting) * @returns an unsubscribe function (to discontinue monitoring) */ function persistQueryClientSubscribe(props) { const unsubscribeQueryCache = props.queryClient.getQueryCache().subscribe(() => { persistQueryClientSave(props); }); const unusbscribeMutationCache = props.queryClient.getMutationCache().subscribe(() => { persistQueryClientSave(props); }); return () => { unsubscribeQueryCache(); unusbscribeMutationCache(); }; } /** * Restores persisted data to QueryCache and persists further changes. */ function persistQueryClient(props) { let hasUnsubscribed = false; let persistQueryClientUnsubscribe; const unsubscribe = () => { hasUnsubscribed = true; persistQueryClientUnsubscribe == null ? void 0 : persistQueryClientUnsubscribe(); }; let restorePromise = Promise.resolve(); if (typeof window !== 'undefined') { // Attempt restore restorePromise = persistQueryClientRestore(props).then(() => { if (!hasUnsubscribed) { // Subscribe to changes in the query cache to trigger the save persistQueryClientUnsubscribe = persistQueryClientSubscribe(props); } }); } return [unsubscribe, restorePromise]; } function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } const defaultContext = /*#__PURE__*/React__default["default"].createContext(undefined); const QueryClientSharingContext = /*#__PURE__*/React__default["default"].createContext(false); // If we are given a context, we will use it. // Otherwise, if contextSharing is on, we share the first and at least one // instance of the context across the window // to ensure that if React Query is used across // different bundles or microfrontends they will // all use the same **instance** of context, regardless // of module scoping. function getQueryClientContext(context, contextSharing) { if (context) { return context; } if (contextSharing && typeof window !== 'undefined') { if (!window.ReactQueryClientContext) { window.ReactQueryClientContext = defaultContext; } return window.ReactQueryClientContext; } return defaultContext; } const QueryClientProvider = ({ client, children, context, contextSharing = false }) => { React__default["default"].useEffect(() => { client.mount(); return () => { client.unmount(); }; }, [client]); const Context = getQueryClientContext(context, contextSharing); return /*#__PURE__*/React__default["default"].createElement(QueryClientSharingContext.Provider, { value: !context && contextSharing }, /*#__PURE__*/React__default["default"].createElement(Context.Provider, { value: client }, children)); }; const IsRestoringContext = /*#__PURE__*/React__default["default"].createContext(false); const IsRestoringProvider = IsRestoringContext.Provider; const PersistQueryClientProvider = ({ client, children, persistOptions, onSuccess, ...props }) => { const [isRestoring, setIsRestoring] = React__default["default"].useState(true); const refs = React__default["default"].useRef({ persistOptions, onSuccess }); React__default["default"].useEffect(() => { refs.current = { persistOptions, onSuccess }; }); React__default["default"].useEffect(() => { let isStale = false; setIsRestoring(true); const [unsubscribe, promise] = persistQueryClient({ ...refs.current.persistOptions, queryClient: client }); promise.then(() => { if (!isStale) { refs.current.onSuccess == null ? void 0 : refs.current.onSuccess(); setIsRestoring(false); } }); return () => { isStale = true; unsubscribe(); }; }, [client]); return /*#__PURE__*/React__default["default"].createElement(QueryClientProvider, _extends({ client: client }, props), /*#__PURE__*/React__default["default"].createElement(IsRestoringProvider, { value: isRestoring }, children)); }; exports.PersistQueryClientProvider = PersistQueryClientProvider; exports.persistQueryClient = persistQueryClient; exports.persistQueryClientRestore = persistQueryClientRestore; exports.persistQueryClientSave = persistQueryClientSave; exports.persistQueryClientSubscribe = persistQueryClientSubscribe; Object.defineProperty(exports, '__esModule', { value: true }); })); //# sourceMappingURL=persistQueryClient.development.js.map