diff --git a/apps/web/components/NextJsExample.tsx b/apps/web/components/NextJsExample.tsx index d70c758a0..56ef7ec91 100644 --- a/apps/web/components/NextJsExample.tsx +++ b/apps/web/components/NextJsExample.tsx @@ -88,18 +88,6 @@ const isRestoringOwner = (isRestoringOwner?: boolean): boolean => { // Ensure fixtures are not added to the restored owner. if (!isRestoringOwner()) createFixtures(); -const logSyncState = (): void => { - evolu.subscribeSyncState(() => { - // eslint-disable-next-line no-console - console.log(evolu.getSyncState()); - }); -}; - -// Ensure logSyncState is called only once with hot reloading. -// Without GlobalValue, people could be confused about why logSyncState -// logs 2x, 3x, etc. -GlobalValue.globalValue("NextJsExample/logSyncState", logSyncState); - export const NextJsExample = memo(function NextJsExample() { const [currentTab, setCurrentTab] = useState<"todos" | "categories">("todos"); @@ -430,3 +418,15 @@ const prompt = ( } onSuccess(a.right); }; + +const logSyncState = (): void => { + evolu.subscribeSyncState(() => { + // eslint-disable-next-line no-console + console.log(evolu.getSyncState()); + }); +}; + +// Ensure logSyncState is called only once with hot reloading. +// Without GlobalValue, people could be confused about why logSyncState +// logs 2x, 3x, etc. +GlobalValue.globalValue("NextJsExample/logSyncState", logSyncState); diff --git a/packages/evolu-common-react/src/index.tsx b/packages/evolu-common-react/src/index.tsx index bc146dc25..47a985a6e 100644 --- a/packages/evolu-common-react/src/index.tsx +++ b/packages/evolu-common-react/src/index.tsx @@ -59,20 +59,39 @@ export interface EvoluReact extends Evolu { ) => QueryResult; /** - * `useQuery` React Hook performs a database query and returns an object with - * `rows` and `row` properties that are automatically updated when data - * changes. + * Load and subscribe to the Query, and return an object with `rows` and `row` + * properties that are automatically updated when data changes. * - * ### Example + * Note that {@link useQuery} uses React Suspense. It means every usage of + * {@link useQuery} blocks rendering until loading is completed. To avoid + * loading waterfall with more queries, use {@link useQueries}. + * + * ### Examples * * ```ts - * const a = 1; + * // Get all rows. + * const { rows } = useQuery(allTodos); + * + * // Get the first row (it can be null). + * const { row } = useQuery(todoById(1)); + * + * // Get all rows, but without subscribing to changes. + * const { rows } = useQuery(allTodos, { once: true }); + * + * // Prefetch all rows + * const allTodos = evolu.createQuery((db) => + * db.selectFrom("todo").selectAll(), + * ); + * // Load before usage. + * const allTodosPromise = evolu.loadQuery(allTodos); + * // A usage. + * const { rows } = useQuery(allTodos, { promise: allTodosPromise }); * ``` */ readonly useQuery: ( query: Query, options?: Partial<{ - /** TODO: B */ + /** Without subscribing to changes. */ readonly once: boolean; /** Reuse existing promise instead of loading so query will not suspense. */ @@ -80,13 +99,7 @@ export interface EvoluReact extends Evolu { }>, ) => QueryResult; - /** - * TODO: Docs For more than one query, always use useQueries Hook to avoid - * loading waterfalls and to cache loading promises. This is possible of - * course: const foo = use(useEvolu().loadQuery(todos)) but it will not cache - * loading promise nor subscribe updates. That's why we have useQuery and - * useQueries. - */ + /** The same as {@link useQuery}, but for many queries. */ readonly useQueries: < R extends Row, Q extends Queries, @@ -94,6 +107,7 @@ export interface EvoluReact extends Evolu { >( queries: [...Q], options?: Partial<{ + /** Queries that should be only loaded, not subscribed to. */ readonly once: [...OQ]; /** Reuse existing promises instead of loading so query will not suspense. */ readonly promises: [