useQuery
useQuery
React Hook performs a database query and returns rows
and
firstRow
props that are automatically updated when data changes. It
takes two callbacks, a Kysely (opens in a new tab)
type-safe SQL query builder, and a filterMap
helper for rows filtering
and ad-hoc migrations.
Note that useQuery
uses React Suspense.
Examples
The most simple example:
const { rows } = useQuery(
(db) => db.selectFrom("todo").selectAll(),
(row) => row
);
If you mouse hover over rows
, you will see that all columns except Id
are nullable regardless of the database Schema.
There are two good reasons for that. The first is the local-first app database schema can be changed anytime, but already-created data can't because it's not feasible to migrate all local data. The second reason is that sync messages can arrive in any order in distributed systems.
The remedy for nullability is ad-hoc filtering and mapping via filterMap
helper. This example filters out rows with falsy titles:
const { rows } = useQuery(
(db) => db.selectFrom("todo").selectAll(),
({ title, ...rest }) => title && { title, ...rest }
);
A real app would filterMap
all versions of the table schema defined
by a union of types, therefore safely enforced by the TypeScript compiler.
The next example shows the usage of columns that Evolu automatically
adds to all tables. Those columns are: createdAt
, createdBy
,
updatedAt
, and isDeleted
.
const { rows } = useQuery(
(db) =>
db
.selectFrom("todoCategory")
.select(["id", "name"])
.where("isDeleted", "is not", E.cast(true))
.orderBy("createdAt"),
({ name, ...rest }) => name && { name, ...rest }
);
Note E.cast
usage. It's Evolu's helper to cast booleans and dates
that SQLite does not support natively.