API reference › @evolu/svelte › queryState

function queryState<
  R extends Row,
  Schema extends Readonly<
    Record<string, Readonly<Record<string, AnyStandardSchemaV1>>>
  >,
>(
  evolu: DeviceEvolu<Schema>,
  observedQuery: () => Query<Schema, R> | undefined,
): QueryState<R>;

Defined in: index.svelte.ts:117

Loads and subscribes to the query that observedQuery returns, and returns a QueryState, whose rows update when the data changes and whose loaded is the current query's first load. A component renders {#await todos.loaded}, what shows while the query loads, {:then}, the rows of todos.rows, {:catch error}, the failure, {/await}, so it tells a loading query from an empty one and shows a failure. See Evolu.loadQuery. It takes any instance, such as an AppOwner's from evoluAppState or the device database's, EvoluApp.device.

It creates an $effect, so call it where Svelte allows one, such as during component initialization or inside $effect.root. The subscription ends when that component or root is destroyed. When observedQuery reads reactive state, such as a $derived query, queryState loads the new query whenever it changes. Derive values from rows with $derived.

Example

Runes such as $state work only in Svelte components and .svelte.ts or .svelte.js modules. A component calls todoTitlesState during its initialization.

import {
  assertType,
  createQueryBuilder,
  sqliteTrue,
  testEvoluSchema,
  type Evolu,
  type NonEmptyTrimmedString100,
  type TestEvoluSchema,
} from "@evolu/common";
import { queryState } from "@evolu/svelte";

const createQuery = createQueryBuilder(testEvoluSchema);

const todoTitlesState = (evolu: Evolu<TestEvoluSchema>) => {
  let showCompleted = $state(false);

  const todosQuery = $derived(
    createQuery((db) =>
      db
        .selectFrom("todo")
        .select(["id", "title"])
        .where("isDeleted", "is not", sqliteTrue)
        .$if(!showCompleted, (qb) =>
          qb.where("isCompleted", "is not", sqliteTrue),
        ),
    ),
  );
  const todos = queryState(evolu, () => todosQuery);
  const titles = $derived(todos.rows.map((todo) => todo.title));

  return {
    titles: () => titles,
    // For `{#await}`, which shows the query loading or its failure.
    loaded: () => todos.loaded,
    toggleCompleted: () => {
      showCompleted = !showCompleted;
    },
  };
};

assertType<
  ReturnType<ReturnType<typeof todoTitlesState>["titles"]>,
  Array<NonEmptyTrimmedString100 | null>
>();
assertType<
  Awaited<
    ReturnType<ReturnType<typeof todoTitlesState>["loaded"]>
  >[number]["title"],
  NonEmptyTrimmedString100 | null
>();