UNPKG

@preact-signals/query

Version:

A reactive utility for React/Preact that simplifies the handling of data fetching and state management. Powered by Preact Signals, it provides hooks and functions to create reactive resources and manage their state seamlessly.

68 lines 3.55 kB
'use client'; import * as React from 'react'; import { useSyncExternalStore } from './useSyncExternalStore'; import { notifyManager, QueriesObserver } from '@tanstack/query-core'; import { useQueryClient } from './QueryClientProvider'; import { useIsRestoring } from './isRestoring'; import { useQueryErrorResetBoundary } from './QueryErrorResetBoundary'; import { ensurePreventErrorBoundaryRetry, getHasError, useClearResetErrorBoundary, } from './errorBoundaryUtils'; import { ensureStaleTime, shouldSuspend, fetchOptimistic, willFetch, } from './suspense'; export function useQueries({ queries, context, }) { const queryClient = useQueryClient({ context }); const isRestoring = useIsRestoring(); const errorResetBoundary = useQueryErrorResetBoundary(); const defaultedQueries = React.useMemo(() => queries.map((options) => { const defaultedOptions = queryClient.defaultQueryOptions(options); // Make sure the results are already in fetching state before subscribing or updating options defaultedOptions._optimisticResults = isRestoring ? 'isRestoring' : 'optimistic'; return defaultedOptions; }), [queries, queryClient, isRestoring]); defaultedQueries.forEach((query) => { ensureStaleTime(query); ensurePreventErrorBoundaryRetry(query, errorResetBoundary); }); useClearResetErrorBoundary(errorResetBoundary); const [observer] = React.useState(() => new QueriesObserver(queryClient, defaultedQueries)); const optimisticResult = observer.getOptimisticResult(defaultedQueries); useSyncExternalStore(React.useCallback((onStoreChange) => isRestoring ? () => undefined : observer.subscribe(notifyManager.batchCalls(onStoreChange)), [observer, isRestoring]), () => observer.getCurrentResult(), () => observer.getCurrentResult()); React.useEffect(() => { // Do not notify on updates because of changes in the options because // these changes should already be reflected in the optimistic result. observer.setQueries(defaultedQueries, { listeners: false }); }, [defaultedQueries, observer]); const shouldAtLeastOneSuspend = optimisticResult.some((result, index) => shouldSuspend(defaultedQueries[index], result, isRestoring)); const suspensePromises = shouldAtLeastOneSuspend ? optimisticResult.flatMap((result, index) => { const options = defaultedQueries[index]; const queryObserver = observer.getObservers()[index]; if (options && queryObserver) { if (shouldSuspend(options, result, isRestoring)) { return fetchOptimistic(options, queryObserver, errorResetBoundary); } else if (willFetch(result, isRestoring)) { void fetchOptimistic(options, queryObserver, errorResetBoundary); } } return []; }) : []; if (suspensePromises.length > 0) { throw Promise.all(suspensePromises); } const observerQueries = observer.getQueries(); const firstSingleResultWhichShouldThrow = optimisticResult.find((result, index) => getHasError({ result, errorResetBoundary, useErrorBoundary: defaultedQueries[index]?.useErrorBoundary ?? false, query: observerQueries[index], })); if (firstSingleResultWhichShouldThrow?.error) { throw firstSingleResultWhichShouldThrow.error; } return optimisticResult; } //# sourceMappingURL=useQueries.js.map