UNPKG

@tanstack/react-db

Version:

React integration for @tanstack/db

118 lines (117 loc) • 4.74 kB
"use client"; import { useRef } from "react"; import { toBoundaryError, rejectLiveQueryInput } from "@tanstack/db"; import { useLiveQueryForSuspense } from "./useLiveQuery.js"; const unscopedErrorScope = {}; const initialRenderErrors = /* @__PURE__ */ new WeakMap(); function clearInitialRenderError(collection, client) { initialRenderErrors.get(collection)?.delete(client ?? unscopedErrorScope); } function rememberInitialRenderError(collection, client, error, clientQuery) { if (collection.status === `cleaned-up`) return; let entry = initialRenderErrors.get(collection); if (!entry) { entry = /* @__PURE__ */ new WeakMap(); collection.once(`status:cleaned-up`, () => { initialRenderErrors.delete(collection); }); initialRenderErrors.set(collection, entry); } entry.set(client ?? unscopedErrorScope, { error, clientQuery }); } function useLiveSuspenseQuery(configOrQueryOrCollection) { const promiseRef = useRef(null); const collectionRef = useRef(null); const hasBeenReadyRef = useRef(false); const { result, client, queryHash, identityError, observer, deferredCollections } = useLiveQueryForSuspense(configOrQueryOrCollection); if (!result.isEnabled) { throw new Error( `useLiveSuspenseQuery does not support disabled queries (callback returned undefined/null). The Suspense pattern requires data to always be defined (T, not T | undefined). Solutions: 1) Use conditional rendering - don't render the component until the condition is met. 2) Use useLiveQuery instead, which supports disabled queries with the 'isEnabled' flag.` ); } const collection = result.collection; try { if (collectionRef.current !== collection) { promiseRef.current = null; collectionRef.current = collection; hasBeenReadyRef.current = false; } const collectionStatus = collection.status; if (result.isReady) { hasBeenReadyRef.current = true; promiseRef.current = null; clearInitialRenderError(collection, client); } const observerError = observer.getError(); const clientQuery = client && queryHash ? client._getLiveQuery(queryHash) : void 0; if (!hasBeenReadyRef.current && (observerError !== void 0 || clientQuery?.status === `error`)) { promiseRef.current = null; throw observerError === void 0 ? clientQuery?.error : observerError; } if (client?._isSsrStreamingEnabled() && !queryHash) { const reason = identityError ? `${identityError.reason} at ${identityError.path}` : `the query has no stable identity`; throw new Error( `Cannot stream this live query during SSR because ${reason}. Provide an explicit serializable queryKey.` ); } const initialRenderError = initialRenderErrors.get(collection)?.get(client ?? unscopedErrorScope); if (initialRenderError?.clientQuery !== void 0 && initialRenderError.clientQuery !== clientQuery) { clearInitialRenderError(collection, client); } else if (initialRenderError && !hasBeenReadyRef.current) { promiseRef.current = null; throw toBoundaryError(initialRenderError.error); } if (collectionStatus === `crashed` || collectionStatus === `error` && !hasBeenReadyRef.current) { promiseRef.current = null; throw toBoundaryError(collection.health.error?.cause); } if (!hasBeenReadyRef.current && (result.isLoading || result.isIdle || result.isLoadingError || result.isCrashed)) { if (!promiseRef.current) { let active = true; const stopWatchingCleanup = collection.once(`status:cleaned-up`, () => { active = false; }); let preload; try { preload = observer.preload(); } catch (error) { stopWatchingCleanup(); throw error; } const preloadClientQuery = client && queryHash ? client._getLiveQuery(queryHash) : void 0; promiseRef.current = preload.catch((error) => { const latestClientQuery = client && queryHash ? client._getLiveQuery(queryHash) : void 0; if (active && latestClientQuery === preloadClientQuery) rememberInitialRenderError( collection, client, error, preloadClientQuery ); throw error; }).finally(stopWatchingCleanup); } throw promiseRef.current; } return { state: result.state, data: result.data, collection, health: result.health }; } catch (error) { if (error instanceof Promise) throw error; return rejectLiveQueryInput(deferredCollections, error); } } export { useLiveSuspenseQuery }; //# sourceMappingURL=useLiveSuspenseQuery.js.map