@tanstack/react-db
Version:
React integration for @tanstack/db
116 lines (115 loc) • 4.91 kB
JavaScript
import { useRef, useCallback, useSyncExternalStore } from "react";
import { normalizeLiveQueryWindowPageSize, getLiveQueryWindowInputKind, compareLiveQueryWindowDependencies, resolveLiveQueryWindowInput, createLiveQueryCollection, getLiveQueryWindowCollectionWarning, assertLiveQueryWindowManyResult, shouldPreserveLiveQueryWindowPageCount, createLiveQueryWindowController, fetchNextLiveQueryWindowPage } from "@tanstack/db";
const DEFAULT_GC_TIME_MS = 1;
function useLiveInfiniteQuery(queryFnOrCollection, config, deps = []) {
const pageSize = normalizeLiveQueryWindowPageSize(config.pageSize);
const initialPageParam = config.initialPageParam ?? 0;
const inputIsCollection = getLiveQueryWindowInputKind(queryFnOrCollection) === `collection`;
const committedRef = useRef(null);
const committed = committedRef.current;
const inputKind = inputIsCollection ? `collection` : `query`;
const dependencyComparison = compareLiveQueryWindowDependencies(
committed?.dependencies,
deps
);
const dependenciesChanged = !inputIsCollection && dependencyComparison.changed;
const dependenciesStructurallyEqual = !inputIsCollection && dependencyComparison.structurallyEqual;
const needsNewCollection = committed === null || committed.inputKind !== inputKind || inputIsCollection && committed.inputCollection !== queryFnOrCollection || dependenciesChanged;
const pageShapeChanged = committed === null || committed.pageSize !== pageSize || committed.initialPageParam !== initialPageParam;
const needsNewController = committed === null || needsNewCollection || pageShapeChanged;
let renderState = committed;
if (needsNewController) {
let collection = committed?.collection;
let warning = null;
if (needsNewCollection) {
const input = resolveLiveQueryWindowInput(queryFnOrCollection);
if (input.kind === `collection`) {
collection = input.collection;
} else {
collection = createLiveQueryCollection({
query: input.query.limit(pageSize + 1).offset(0),
// Construction happens during render. Synchronization starts only when
// useSyncExternalStore commits the controller subscription.
startSync: false,
gcTime: DEFAULT_GC_TIME_MS
});
}
}
if (!collection) {
throw new Error(`useLiveInfiniteQuery: Failed to create a collection.`);
}
if (inputIsCollection) {
warning = getLiveQueryWindowCollectionWarning(collection, pageSize + 1) ?? null;
} else {
assertLiveQueryWindowManyResult(collection);
}
const canPreservePageCount = shouldPreserveLiveQueryWindowPageCount({
hasPreviousController: committed !== null,
previousInputKind: committed?.inputKind,
inputKind,
sameCollection: inputIsCollection && committed?.inputCollection === collection,
dependenciesChanged,
dependenciesStructurallyEqual,
pageShapeChanged
});
const previousPageCount = committed ? Math.max(1, committed.controller.getSnapshot().pages.length) : 1;
const initialPageCount = canPreservePageCount ? previousPageCount : 1;
renderState = {
inputKind,
inputCollection: inputIsCollection ? collection : null,
dependencies: inputIsCollection ? null : [...deps],
pageSize,
initialPageParam,
collection,
controller: createLiveQueryWindowController(collection, {
pageSize,
initialPageParam,
initialPageCount
}),
warning,
warned: false
};
}
const currentRenderState = renderState;
const controller = currentRenderState.controller;
const subscribe = useCallback(
(onStoreChange) => {
const unsubscribe = controller.subscribe(onStoreChange);
committedRef.current = currentRenderState;
if (currentRenderState.warning && !currentRenderState.warned) {
currentRenderState.warned = true;
console.warn(currentRenderState.warning);
}
return unsubscribe;
},
[controller, currentRenderState]
);
const getSnapshot = useCallback(() => controller.getSnapshot(), [controller]);
const snapshot = useSyncExternalStore(subscribe, getSnapshot);
const fetchNextPage = useCallback(
() => fetchNextLiveQueryWindowPage(controller),
[controller]
);
return {
data: snapshot.data,
state: snapshot.state,
status: snapshot.status,
isLoading: snapshot.isLoading,
isReady: snapshot.isReady,
isIdle: snapshot.isIdle,
isError: snapshot.isError,
isCleanedUp: snapshot.isCleanedUp,
collection: snapshot.collection,
isEnabled: snapshot.isEnabled,
pages: snapshot.pages,
pageParams: snapshot.pageParams,
fetchNextPage,
hasNextPage: snapshot.hasNextPage,
isFetchingNextPage: snapshot.isFetchingNextPage,
error: snapshot.error
};
}
export {
useLiveInfiniteQuery
};
//# sourceMappingURL=useLiveInfiniteQuery.js.map