import { constVoid } from "@evolu/common"; import { Query, QueryRows, Row, emptyRows } from "@evolu/common/local-first"; import { useEffect, useMemo, useRef, useSyncExternalStore } from "react"; import { useEvolu } from "./useEvolu.js"; /** Subscribe to {@link Query} {@link QueryRows} changes. */ export const useQuerySubscription = ( query: Query, options: Partial<{ /** * Only subscribe and get the current value once. Subscribed query will not * invoke React Suspense after a mutation. */ readonly once: boolean; }> = {}, ): QueryRows => { const evolu = useEvolu(); // useRef to not break "rules-of-hooks" const { once } = useRef(options).current; if (once) { /* eslint-disable react-hooks/rules-of-hooks */ useEffect( // No useSyncExternalStore, no unnecessary updates. () => evolu.subscribeQuery(query)(constVoid), [evolu, query], ); return evolu.getQueryRows(query); } return useSyncExternalStore( useMemo(() => evolu.subscribeQuery(query), [evolu, query]), useMemo(() => () => evolu.getQueryRows(query), [evolu, query]), () => emptyRows as QueryRows, /* eslint-enable react-hooks/rules-of-hooks */ ); };