Skip to content

Expo

  • Recommended: Bun 1.2 or higher
  • Node.js 23.0.0 or higher

To use LiveStore with Expo, ensure your project has the New Architecture enabled. This is required for transactional state updates.

For a quick start we recommend using our template app following the steps below.

For existing projects see Existing project setup.

  1. Set up project from template

    Terminal window
    bunx @livestore/cli@dev create --example expo-todomvc-sync-cf livestore-app

    Replace livestore-app with your desired app name.

  2. Install dependencies

    It’s strongly recommended to use bun or pnpm for the simplest and most reliable dependency setup (see note on package management for more details).

    Terminal window
    bun install

    Pro tip: You can use direnv to manage environment variables.

  3. Run the app

    Terminal window
    bun start

    In a new terminal, start the Cloudflare Worker (for the sync backend):

    Terminal window
    bun wrangler:dev
  1. Install dependencies

    Terminal window
    bun install @livestore/devtools-expo@0.4.0-dev.14 @livestore/adapter-expo@0.4.0-dev.14 @livestore/livestore@0.4.0-dev.14 @livestore/react@0.4.0-dev.14 @livestore/sync-cf/client@0.4.0-dev.14 @livestore/peer-deps@0.4.0-dev.14 expo-sqlite
  2. Add Vite meta plugin to babel config file

    LiveStore Devtools uses Vite. This plugin emulates Vite’s import.meta.env functionality.

    Terminal window
    bun add -d babel-plugin-transform-vite-meta-env

    In your babel.config.js file, add the plugin as follows:

    babel.config.js
    module.exports = (api) => {
    api.cache(true)
    return {
    presets: [['babel-preset-expo', { unstable_transformImportMeta: true }]],
    plugins: ['babel-plugin-transform-vite-meta-env', '@babel/plugin-syntax-import-attributes'],
    }
    }
  3. Update Metro config

    Add the following code to your metro.config.js file:

    metro.config.js
    // Learn more https://docs.expo.io/guides/customizing-metro
    const { getDefaultConfig } = require('expo/metro-config')
    const { addLiveStoreDevtoolsMiddleware } = require('@livestore/devtools-expo')
    const path = require('node:path')
    /** @type {import('expo/metro-config').MetroConfig} */
    const config = getDefaultConfig(__dirname)
    // Needed for monorepo setup (can be removed in standalone projects)
    if (process.env.MONOREPO_ROOT) {
    config.watchFolders = [path.resolve(process.env.MONOREPO_ROOT)]
    }
    addLiveStoreDevtoolsMiddleware(config, {
    schemaPath: './src/livestore/schema.ts',
    viteConfig: (viteConfig) => {
    viteConfig.server.fs ??= {}
    viteConfig.server.fs.strict = false
    viteConfig.optimizeDeps ??= {}
    viteConfig.optimizeDeps.force = true
    return viteConfig
    },
    })
    module.exports = config

Create a file named schema.ts inside the src/livestore folder. This file defines your LiveStore schema consisting of your app’s event definitions (describing how data changes), derived state (i.e. SQLite tables), and materializers (how state is derived from events).

Here’s an example schema:

import {
import Events
Events
,
const makeSchema: <TInputSchema extends InputSchema>(inputSchema: TInputSchema) => FromInputSchema.DeriveSchema<TInputSchema>
makeSchema
,
import Schema
Schema
,
type SessionIdSymbol = typeof SessionIdSymbol
const SessionIdSymbol: typeof SessionIdSymbol

Can be used in queries to refer to the current session id. Will be replaced with the actual session id at runtime

In client document table:

const uiState = State.SQLite.clientDocument({
name: 'ui_state',
schema: Schema.Struct({
theme: Schema.Literal('dark', 'light', 'system'),
user: Schema.String,
showToolbar: Schema.Boolean,
}),
default: { value: defaultFrontendState, id: SessionIdSymbol },
})

Or in a client document query:

const query$ = queryDb(tables.uiState.get(SessionIdSymbol))

SessionIdSymbol
,
import State
State
} from '@livestore/livestore'
export const
const tables: {
todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>;
uiState: State.SQLite.ClientDocumentTableDef<...>;
}
tables
= {
todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>
todos
:
import State
State
.
import SQLite
SQLite
.
function table<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
columnType: "integer";
... 4 more ...;
autoIncrement: false;
};
}, Partial<...>>(args: {
...;
} & Partial<...>): State.SQLite.TableDef<...> (+2 overloads)

Creates a SQLite table definition from columns or an Effect Schema.

This function supports two main ways to define a table:

  1. Using explicit column definitions
  2. Using an Effect Schema (either the name property needs to be provided or the schema needs to have a title/identifier)
// Using explicit columns
const usersTable = State.SQLite.table({
name: 'users',
columns: {
id: State.SQLite.text({ primaryKey: true }),
name: State.SQLite.text({ nullable: false }),
email: State.SQLite.text({ nullable: false }),
age: State.SQLite.integer({ nullable: true }),
},
})
// Using Effect Schema with annotations
import { Schema } from '@livestore/utils/effect'
const UserSchema = Schema.Struct({
id: Schema.Int.pipe(State.SQLite.withPrimaryKey).pipe(State.SQLite.withAutoIncrement),
email: Schema.String.pipe(State.SQLite.withUnique),
name: Schema.String,
active: Schema.Boolean.pipe(State.SQLite.withDefault(true)),
createdAt: Schema.optional(Schema.Date),
})
// Option 1: With explicit name
const usersTable = State.SQLite.table({
name: 'users',
schema: UserSchema,
})
// Option 2: With name from schema annotation (title or identifier)
const AnnotatedUserSchema = UserSchema.annotations({ title: 'users' })
const usersTable2 = State.SQLite.table({
schema: AnnotatedUserSchema,
})
// Adding indexes
const PostSchema = Schema.Struct({
id: Schema.String.pipe(State.SQLite.withPrimaryKey),
title: Schema.String,
authorId: Schema.String,
createdAt: Schema.Date,
}).annotations({ identifier: 'posts' })
const postsTable = State.SQLite.table({
schema: PostSchema,
indexes: [
{ name: 'idx_posts_author', columns: ['authorId'] },
{ name: 'idx_posts_created', columns: ['createdAt'], isUnique: false },
],
})

table
({
name: "todos"
name
: 'todos',
columns: {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
...;
};
}
columns
: {
id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
}
id
:
import State
State
.
import SQLite
SQLite
.
const text: <string, string, false, typeof NoDefault, true, false>(args: {
schema?: Schema.Schema<string, string, never>;
default?: typeof NoDefault;
nullable?: false;
primaryKey?: true;
autoIncrement?: false;
}) => {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
} (+1 overload)
text
({
primaryKey?: true
primaryKey
: true }),
text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
}
text
:
import State
State
.
import SQLite
SQLite
.
const text: <string, string, false, "", false, false>(args: {
schema?: Schema.Schema<string, string, never>;
default?: "";
nullable?: false;
primaryKey?: false;
autoIncrement?: false;
}) => {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
} (+1 overload)
text
({
default?: ""
default
: '' }),
completed: {
columnType: "integer";
schema: Schema.Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
}
completed
:
import State
State
.
import SQLite
SQLite
.
const boolean: <boolean, false, false, false, false>(args: {
default?: false;
nullable?: false;
primaryKey?: false;
autoIncrement?: false;
}) => {
columnType: "integer";
schema: Schema.Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
} (+1 overload)
boolean
({
default?: false
default
: false }),
deletedAt: {
columnType: "integer";
schema: Schema.Schema<Date | null, number | null, never>;
default: None<never>;
nullable: true;
primaryKey: false;
autoIncrement: false;
}
deletedAt
:
import State
State
.
import SQLite
SQLite
.
const integer: <number, Date, true, typeof NoDefault, false, false>(args: {
schema?: Schema.Schema<Date, number, never>;
default?: typeof NoDefault;
nullable?: true;
primaryKey?: false;
autoIncrement?: false;
}) => {
columnType: "integer";
schema: Schema.Schema<Date | null, number | null, never>;
default: None<never>;
nullable: true;
primaryKey: false;
autoIncrement: false;
} (+1 overload)
integer
({
nullable?: true
nullable
: true,
schema?: Schema.Schema<Date, number, never>
schema
:
import Schema
Schema
.
class DateFromNumber

Defines a schema that converts a number into a Date object using the new Date constructor. This schema does not validate the numerical input, allowing potentially invalid values such as NaN, Infinity, and -Infinity to be converted into Date objects. During the encoding process, any invalid Date object will be encoded to NaN.

@since3.10.0

DateFromNumber
}),
},
}),
uiState: State.SQLite.ClientDocumentTableDef<"uiState", {
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
}, {
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
}, {
partialSet: true;
default: {
id: typeof SessionIdSymbol;
value: {
readonly newTodoText: "";
readonly filter: "all";
};
};
}>
uiState
:
import State
State
.
import SQLite
SQLite
.
clientDocument<"uiState", {
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
}, {
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
}, {
readonly name: "uiState";
readonly schema: Schema.Struct<{
newTodoText: typeof Schema.String;
filter: Schema.Literal<["all", "active", "completed"]>;
}>;
readonly default: {
readonly id: typeof SessionIdSymbol;
readonly value: {
readonly newTodoText: "";
readonly filter: "all";
};
};
}>({ name, schema: valueSchema, ...inputOptions }: {
name: "uiState";
schema: Schema.Schema<{
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
}, {
...;
}, never>;
} & {
readonly name: "uiState";
readonly schema: Schema.Struct<{
newTodoText: typeof Schema.String;
filter: Schema.Literal<["all", "active", "completed"]>;
}>;
readonly default: {
readonly id: typeof SessionIdSymbol;
readonly value: {
readonly newTodoText: "";
readonly filter: "all";
};
};
}): State.SQLite.ClientDocumentTableDef<...>
export clientDocument

Special:

  • Synced across client sessions (e.g. tabs) but not across different clients
  • Derived setters
    • Emits client-only events
    • Has implicit setter-materializers
  • Similar to React.useState (except it's persisted)

Careful:

  • When changing the table definitions in a non-backwards compatible way, the state might be lost without explicit materializers to handle the old auto-generated events

Usage:

// Querying data
// `'some-id'` can be ommited for SessionIdSymbol
store.queryDb(clientDocumentTable.get('some-id'))
// Setting data
// Again, `'some-id'` can be ommited for SessionIdSymbol
store.commit(clientDocumentTable.set({ someField: 'some-value' }, 'some-id'))

clientDocument
({
name: "uiState"
name
: 'uiState',
schema: Schema.Schema<{
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
}, {
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
}, never> & Schema.Struct<{
newTodoText: typeof Schema.String;
filter: Schema.Literal<["all", "active", "completed"]>;
}>
schema
:
import Schema
Schema
.
function Struct<{
newTodoText: typeof Schema.String;
filter: Schema.Literal<["all", "active", "completed"]>;
}>(fields: {
newTodoText: typeof Schema.String;
filter: Schema.Literal<["all", "active", "completed"]>;
}): Schema.Struct<{
newTodoText: typeof Schema.String;
filter: Schema.Literal<["all", "active", "completed"]>;
}> (+1 overload)

@since3.10.0

Struct
({
newTodoText: typeof Schema.String
newTodoText
:
import Schema
Schema
.
class String
export String

@since3.10.0

String
,
filter: Schema.Literal<["all", "active", "completed"]>
filter
:
import Schema
Schema
.
function Literal<["all", "active", "completed"]>(literals_0: "all", literals_1: "active", literals_2: "completed"): Schema.Literal<["all", "active", "completed"]> (+2 overloads)

@since3.10.0

Literal
('all', 'active', 'completed') }),
default: {
readonly id: typeof SessionIdSymbol;
readonly value: {
readonly newTodoText: "";
readonly filter: "all";
};
}
default
: {
id: typeof SessionIdSymbol
id
:
const SessionIdSymbol: typeof SessionIdSymbol

Can be used in queries to refer to the current session id. Will be replaced with the actual session id at runtime

In client document table:

const uiState = State.SQLite.clientDocument({
name: 'ui_state',
schema: Schema.Struct({
theme: Schema.Literal('dark', 'light', 'system'),
user: Schema.String,
showToolbar: Schema.Boolean,
}),
default: { value: defaultFrontendState, id: SessionIdSymbol },
})

Or in a client document query:

const query$ = queryDb(tables.uiState.get(SessionIdSymbol))

SessionIdSymbol
,
value: {
readonly newTodoText: "";
readonly filter: "all";
}
value
: {
newTodoText: ""
newTodoText
: '',
filter: "all"
filter
: 'all' } },
}),
}
export const
const events: {
todoCreated: State.SQLite.EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>;
todoCompleted: State.SQLite.EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: State.SQLite.EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: State.SQLite.EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: State.SQLite.EventDef<...>;
uiStateSet: State.SQLite.ClientDocumentTableDef.SetEventDefLike<...>;
}
events
= {
todoCreated: State.SQLite.EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>
todoCreated
:
import Events
Events
.
synced<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}>(args: {
name: "v1.TodoCreated";
schema: Schema.Schema<{
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, never>;
} & Omit<State.SQLite.DefineEventOptions<{
readonly text: string;
readonly id: string;
}, false>, "derived" | "clientOnly">): State.SQLite.EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>
export synced
synced
({
name: "v1.TodoCreated"
name
: 'v1.TodoCreated',
schema: Schema.Schema<{
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, never>
schema
:
import Schema
Schema
.
function Struct<{
id: typeof Schema.String;
text: typeof Schema.String;
}>(fields: {
id: typeof Schema.String;
text: typeof Schema.String;
}): Schema.Struct<{
id: typeof Schema.String;
text: typeof Schema.String;
}> (+1 overload)

@since3.10.0

Struct
({
id: typeof Schema.String
id
:
import Schema
Schema
.
class String
export String

@since3.10.0

String
,
text: typeof Schema.String
text
:
import Schema
Schema
.
class String
export String

@since3.10.0

String
}),
}),
todoCompleted: State.SQLite.EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>
todoCompleted
:
import Events
Events
.
synced<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}>(args: {
name: "v1.TodoCompleted";
schema: Schema.Schema<{
readonly id: string;
}, {
readonly id: string;
}, never>;
} & Omit<State.SQLite.DefineEventOptions<{
readonly id: string;
}, false>, "derived" | "clientOnly">): State.SQLite.EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>
export synced
synced
({
name: "v1.TodoCompleted"
name
: 'v1.TodoCompleted',
schema: Schema.Schema<{
readonly id: string;
}, {
readonly id: string;
}, never>
schema
:
import Schema
Schema
.
function Struct<{
id: typeof Schema.String;
}>(fields: {
id: typeof Schema.String;
}): Schema.Struct<{
id: typeof Schema.String;
}> (+1 overload)

@since3.10.0

Struct
({
id: typeof Schema.String
id
:
import Schema
Schema
.
class String
export String

@since3.10.0

String
}),
}),
todoUncompleted: State.SQLite.EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>
todoUncompleted
:
import Events
Events
.
synced<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}>(args: {
name: "v1.TodoUncompleted";
schema: Schema.Schema<{
readonly id: string;
}, {
readonly id: string;
}, never>;
} & Omit<State.SQLite.DefineEventOptions<{
readonly id: string;
}, false>, "derived" | "clientOnly">): State.SQLite.EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>
export synced
synced
({
name: "v1.TodoUncompleted"
name
: 'v1.TodoUncompleted',
schema: Schema.Schema<{
readonly id: string;
}, {
readonly id: string;
}, never>
schema
:
import Schema
Schema
.
function Struct<{
id: typeof Schema.String;
}>(fields: {
id: typeof Schema.String;
}): Schema.Struct<{
id: typeof Schema.String;
}> (+1 overload)

@since3.10.0

Struct
({
id: typeof Schema.String
id
:
import Schema
Schema
.
class String
export String

@since3.10.0

String
}),
}),
todoDeleted: State.SQLite.EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>
todoDeleted
:
import Events
Events
.
synced<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}>(args: {
name: "v1.TodoDeleted";
schema: Schema.Schema<{
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, never>;
} & Omit<State.SQLite.DefineEventOptions<{
readonly id: string;
readonly deletedAt: Date;
}, false>, "derived" | "clientOnly">): State.SQLite.EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>
export synced
synced
({
name: "v1.TodoDeleted"
name
: 'v1.TodoDeleted',
schema: Schema.Schema<{
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, never>
schema
:
import Schema
Schema
.
function Struct<{
id: typeof Schema.String;
deletedAt: typeof Schema.Date;
}>(fields: {
id: typeof Schema.String;
deletedAt: typeof Schema.Date;
}): Schema.Struct<{
id: typeof Schema.String;
deletedAt: typeof Schema.Date;
}> (+1 overload)

@since3.10.0

Struct
({
id: typeof Schema.String
id
:
import Schema
Schema
.
class String
export String

@since3.10.0

String
,
deletedAt: typeof Schema.Date
deletedAt
:
import Schema
Schema
.
class Date
export Date

This schema converts a string into a Date object using the new Date constructor. It ensures that only valid date strings are accepted, rejecting any strings that would result in an invalid date, such as new Date("Invalid Date").

@since3.10.0

Date
}),
}),
todoClearedCompleted: State.SQLite.EventDef<"v1.TodoClearedCompleted", {
readonly deletedAt: Date;
}, {
readonly deletedAt: string;
}, false>
todoClearedCompleted
:
import Events
Events
.
synced<"v1.TodoClearedCompleted", {
readonly deletedAt: Date;
}, {
readonly deletedAt: string;
}>(args: {
name: "v1.TodoClearedCompleted";
schema: Schema.Schema<{
readonly deletedAt: Date;
}, {
readonly deletedAt: string;
}, never>;
} & Omit<State.SQLite.DefineEventOptions<{
readonly deletedAt: Date;
}, false>, "derived" | "clientOnly">): State.SQLite.EventDef<"v1.TodoClearedCompleted", {
readonly deletedAt: Date;
}, {
readonly deletedAt: string;
}, false>
export synced
synced
({
name: "v1.TodoClearedCompleted"
name
: 'v1.TodoClearedCompleted',
schema: Schema.Schema<{
readonly deletedAt: Date;
}, {
readonly deletedAt: string;
}, never>
schema
:
import Schema
Schema
.
function Struct<{
deletedAt: typeof Schema.Date;
}>(fields: {
deletedAt: typeof Schema.Date;
}): Schema.Struct<{
deletedAt: typeof Schema.Date;
}> (+1 overload)

@since3.10.0

Struct
({
deletedAt: typeof Schema.Date
deletedAt
:
import Schema
Schema
.
class Date
export Date

This schema converts a string into a Date object using the new Date constructor. It ensures that only valid date strings are accepted, rejecting any strings that would result in an invalid date, such as new Date("Invalid Date").

@since3.10.0

Date
}),
}),
uiStateSet: State.SQLite.ClientDocumentTableDef.SetEventDefLike<"uiState", {
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
}, {
partialSet: true;
default: {
id: typeof SessionIdSymbol;
value: {
readonly newTodoText: "";
readonly filter: "all";
};
};
}>
uiStateSet
:
const tables: {
todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>;
uiState: State.SQLite.ClientDocumentTableDef<...>;
}
tables
.
uiState: State.SQLite.ClientDocumentTableDef<"uiState", {
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
}, {
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
}, {
partialSet: true;
default: {
id: typeof SessionIdSymbol;
value: {
readonly newTodoText: "";
readonly filter: "all";
};
};
}>
uiState
.
ClientDocumentTableDef<TName extends string, TType, TEncoded, TOptions extends ClientDocumentTableOptions<TType>>.Trait<"uiState", { readonly filter: "completed" | "all" | "active"; readonly newTodoText: string; }, { readonly filter: "completed" | "all" | "active"; readonly newTodoText: string; }, { ...; }>.set: State.SQLite.ClientDocumentTableDef.SetEventDefLike<"uiState", {
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
}, {
partialSet: true;
default: {
id: typeof SessionIdSymbol;
value: {
readonly newTodoText: "";
readonly filter: "all";
};
};
}>

Derived event definition for setting the value of the client document table. If the document doesn't exist yet, the first .set event will create it.

@example

const someDocumentTable = State.SQLite.clientDocument({
name: 'SomeDocumentTable',
schema: Schema.Struct({
someField: Schema.String,
someOtherField: Schema.String,
}),
default: { value: { someField: 'some-default-value', someOtherField: 'some-other-default-value' } },
})
const setEventDef = store.commit(someDocumentTable.set({ someField: 'explicit-value' }, 'some-id'))
// Will commit an event with the following payload:
// { id: 'some-id', value: { someField: 'explicit-value', someOtherField: 'some-other-default-value' } }

Similar to .get, you can omit the id argument if you've set a default id.

@example

const uiState = State.SQLite.clientDocument({
name: 'UiState',
schema: Schema.Struct({ someField: Schema.String }),
default: { id: SessionIdSymbol, value: { someField: 'some-default-value' } },
})
const setEventDef = store.commit(uiState.set({ someField: 'explicit-value' }))
// Will commit an event with the following payload:
// { id: '...', value: { someField: 'explicit-value' } }
// ^^^
// Automatically replaced with the client session id

set
,
}
const
const materializers: {
"v1.TodoCreated": State.SQLite.Materializer<State.SQLite.EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>>;
"v1.TodoCompleted": State.SQLite.Materializer<State.SQLite.EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>>;
"v1.TodoUncompleted": State.SQLite.Materializer<State.SQLite.EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>>;
"v1.TodoDeleted": State.SQLite.Materializer<...>;
"v1.TodoClearedCompleted": State.SQLite.Materializer<...>;
}
materializers
=
import State
State
.
import SQLite
SQLite
.
const materializers: <{
todoCreated: State.SQLite.EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>;
todoCompleted: State.SQLite.EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: State.SQLite.EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: State.SQLite.EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: State.SQLite.EventDef<...>;
uiStateSet: State.SQLite.ClientDocumentTableDef.SetEventDefLike<...>;
}>(_eventDefRecord: {
todoCreated: State.SQLite.EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>;
todoCompleted: State.SQLite.EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: State.SQLite.EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: State.SQLite.EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: State.SQLite.EventDef<...>;
uiStateSet: State.SQLite.ClientDocumentTableDef.SetEventDefLike<...>;
}, handlers: {
...;
}) => {
...;
}
materializers
(
const events: {
todoCreated: State.SQLite.EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>;
todoCompleted: State.SQLite.EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: State.SQLite.EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: State.SQLite.EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: State.SQLite.EventDef<...>;
uiStateSet: State.SQLite.ClientDocumentTableDef.SetEventDefLike<...>;
}
events
, {
'v1.TodoCreated': ({
id: string
id
,
text: string
text
}) =>
const tables: {
todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>;
uiState: State.SQLite.ClientDocumentTableDef<...>;
}
tables
.
todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>
todos
.
insert: (values: {
readonly id: string;
readonly text?: string;
readonly completed?: boolean;
readonly deletedAt?: Date | null;
}) => QueryBuilder<readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}[], State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
...;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>>, "select" | ... 6 more ... | "row">

Insert a new row into the table

Example:

db.todos.insert({ id: '123', text: 'Buy milk', status: 'active' })

insert
({
id: string
id
,
text?: string
text
,
completed?: boolean
completed
: false }),
'v1.TodoCompleted': ({
id: string
id
}) =>
const tables: {
todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>;
uiState: State.SQLite.ClientDocumentTableDef<...>;
}
tables
.
todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>
todos
.
update: (values: Partial<{
readonly text: string;
readonly id: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}>) => QueryBuilder<readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}[], State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
...;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>>, "select" | ... 6 more ... | "row">

Update rows in the table that match the where clause

Example:

db.todos.update({ status: 'completed' }).where({ id: '123' })

update
({
completed?: boolean
completed
: true }).
where: (params: Partial<{
readonly id: string | {
op: QueryBuilder<TResult, TTableDef extends State.SQLite.TableDefBase, TWithout extends QueryBuilder.ApiFeature = never>.WhereOps.SingleValue;
value: string;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly string[];
} | undefined;
readonly text: string | {
op: QueryBuilder.WhereOps.SingleValue;
value: string;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly string[];
} | undefined;
readonly completed: boolean | ... 2 more ... | undefined;
readonly deletedAt: Date | ... 3 more ... | undefined;
}>) => QueryBuilder<...> (+2 overloads)
where
({
id?: string | {
op: QueryBuilder.WhereOps.SingleValue;
value: string;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly string[];
} | undefined
id
}),
'v1.TodoUncompleted': ({
id: string
id
}) =>
const tables: {
todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>;
uiState: State.SQLite.ClientDocumentTableDef<...>;
}
tables
.
todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>
todos
.
update: (values: Partial<{
readonly text: string;
readonly id: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}>) => QueryBuilder<readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}[], State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
...;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>>, "select" | ... 6 more ... | "row">

Update rows in the table that match the where clause

Example:

db.todos.update({ status: 'completed' }).where({ id: '123' })

update
({
completed?: boolean
completed
: false }).
where: (params: Partial<{
readonly id: string | {
op: QueryBuilder<TResult, TTableDef extends State.SQLite.TableDefBase, TWithout extends QueryBuilder.ApiFeature = never>.WhereOps.SingleValue;
value: string;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly string[];
} | undefined;
readonly text: string | {
op: QueryBuilder.WhereOps.SingleValue;
value: string;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly string[];
} | undefined;
readonly completed: boolean | ... 2 more ... | undefined;
readonly deletedAt: Date | ... 3 more ... | undefined;
}>) => QueryBuilder<...> (+2 overloads)
where
({
id?: string | {
op: QueryBuilder.WhereOps.SingleValue;
value: string;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly string[];
} | undefined
id
}),
'v1.TodoDeleted': ({
id: string
id
,
deletedAt: Date
deletedAt
}) =>
const tables: {
todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>;
uiState: State.SQLite.ClientDocumentTableDef<...>;
}
tables
.
todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>
todos
.
update: (values: Partial<{
readonly text: string;
readonly id: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}>) => QueryBuilder<readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}[], State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
...;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>>, "select" | ... 6 more ... | "row">

Update rows in the table that match the where clause

Example:

db.todos.update({ status: 'completed' }).where({ id: '123' })

update
({
deletedAt?: Date | null
deletedAt
}).
where: (params: Partial<{
readonly id: string | {
op: QueryBuilder<TResult, TTableDef extends State.SQLite.TableDefBase, TWithout extends QueryBuilder.ApiFeature = never>.WhereOps.SingleValue;
value: string;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly string[];
} | undefined;
readonly text: string | {
op: QueryBuilder.WhereOps.SingleValue;
value: string;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly string[];
} | undefined;
readonly completed: boolean | ... 2 more ... | undefined;
readonly deletedAt: Date | ... 3 more ... | undefined;
}>) => QueryBuilder<...> (+2 overloads)
where
({
id?: string | {
op: QueryBuilder.WhereOps.SingleValue;
value: string;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly string[];
} | undefined
id
}),
'v1.TodoClearedCompleted': ({
deletedAt: Date
deletedAt
}) =>
const tables: {
todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>;
uiState: State.SQLite.ClientDocumentTableDef<...>;
}
tables
.
todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>
todos
.
update: (values: Partial<{
readonly text: string;
readonly id: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}>) => QueryBuilder<readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}[], State.SQLite.TableDefBase<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
...;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>>, "select" | ... 6 more ... | "row">

Update rows in the table that match the where clause

Example:

db.todos.update({ status: 'completed' }).where({ id: '123' })

update
({
deletedAt?: Date | null
deletedAt
}).
where: (params: Partial<{
readonly id: string | {
op: QueryBuilder<TResult, TTableDef extends State.SQLite.TableDefBase, TWithout extends QueryBuilder.ApiFeature = never>.WhereOps.SingleValue;
value: string;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly string[];
} | undefined;
readonly text: string | {
op: QueryBuilder.WhereOps.SingleValue;
value: string;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly string[];
} | undefined;
readonly completed: boolean | ... 2 more ... | undefined;
readonly deletedAt: Date | ... 3 more ... | undefined;
}>) => QueryBuilder<...> (+2 overloads)
where
({
completed?: boolean | {
op: QueryBuilder.WhereOps.SingleValue;
value: boolean;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly boolean[];
} | undefined
completed
: true }),
})
const
const state: InternalState
state
=
import State
State
.
import SQLite
SQLite
.
const makeState: <{
tables: {
todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>;
uiState: State.SQLite.ClientDocumentTableDef<...>;
};
materializers: {
...;
};
}>(inputSchema: {
tables: {
todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>;
uiState: State.SQLite.ClientDocumentTableDef<...>;
};
materializers: {
...;
};
}) => InternalState
makeState
({
tables: {
todos: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema.Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema.Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
...;
};
}>, State.SQLite.WithDefaults<...>, Schema.Schema<...>>;
uiState: State.SQLite.ClientDocumentTableDef<...>;
}
tables
,
materializers: {
"v1.TodoCreated": State.SQLite.Materializer<State.SQLite.EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>>;
"v1.TodoCompleted": State.SQLite.Materializer<State.SQLite.EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>>;
"v1.TodoUncompleted": State.SQLite.Materializer<State.SQLite.EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>>;
"v1.TodoDeleted": State.SQLite.Materializer<...>;
"v1.TodoClearedCompleted": State.SQLite.Materializer<...>;
}
materializers
})
export const
const schema: FromInputSchema.DeriveSchema<{
events: {
todoCreated: State.SQLite.EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>;
todoCompleted: State.SQLite.EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: State.SQLite.EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: State.SQLite.EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: State.SQLite.EventDef<...>;
uiStateSet: State.SQLite.ClientDocumentTableDef.SetEventDefLike<...>;
};
state: InternalState;
}>
schema
=
makeSchema<{
events: {
todoCreated: State.SQLite.EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>;
todoCompleted: State.SQLite.EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: State.SQLite.EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: State.SQLite.EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: State.SQLite.EventDef<...>;
uiStateSet: State.SQLite.ClientDocumentTableDef.SetEventDefLike<...>;
};
state: InternalState;
}>(inputSchema: {
events: {
todoCreated: State.SQLite.EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>;
todoCompleted: State.SQLite.EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: State.SQLite.EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: State.SQLite.EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: State.SQLite.EventDef<...>;
uiStateSet: State.SQLite.ClientDocumentTableDef.SetEventDefLike<...>;
};
state: InternalState;
}): FromInputSchema.DeriveSchema<...>
makeSchema
({
events: {
todoCreated: State.SQLite.EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>;
todoCompleted: State.SQLite.EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: State.SQLite.EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: State.SQLite.EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: State.SQLite.EventDef<...>;
uiStateSet: State.SQLite.ClientDocumentTableDef.SetEventDefLike<...>;
}
events
,
state: InternalState
state
})

To make the LiveStore available throughout your app, wrap your app’s root component with the LiveStoreProvider component from @livestore/react. This provider manages your app’s data store, loading, and error states.

Here’s an example:

import {
const makePersistedAdapter: (options?: MakeDbOptions) => Adapter
makePersistedAdapter
} from '@livestore/adapter-expo'
import {
const LiveStoreProvider: <TSyncPayloadSchema extends Schema<any> = Schema<JsonValue, JsonValue, never>>({ renderLoading, renderError, renderShutdown, otelOptions, children, schema, storeId, boot, adapter, batchUpdates, disableDevtools, signal, confirmUnsavedChanges, syncPayload, syncPayloadSchema, debug, }: LiveStoreProviderProps<TSyncPayloadSchema> & React.PropsWithChildren) => React.ReactNode
LiveStoreProvider
} from '@livestore/react'
import {
const makeWsSync: (options: WsSyncOptions) => SyncBackendConstructor<SyncMetadata>

Creates a sync backend that uses WebSocket to communicate with the sync backend.

@example

import { makeWsSync } from '@livestore/sync-cf/client'
const syncBackend = makeWsSync({ url: 'wss://sync.example.com' })

makeWsSync
} from '@livestore/sync-cf/client'
import {
function StatusBar({ style, hideTransitionAnimation, translucent, backgroundColor: backgroundColorProp, ...props }: StatusBarProps): React.JSX.Element

A component that allows you to configure your status bar without directly calling imperative methods like setBarStyle.

You will likely have multiple StatusBar components mounted in the same app at the same time. For example, if you have multiple screens in your app, you may end up using one per screen. The props of each StatusBar component will be merged in the order that they were mounted. This component is built on top of the StatusBar component exported from React Native, and it provides defaults that work better for Expo users.

StatusBar
} from 'expo-status-bar'
import type {
type FC<P = {}> = React.FunctionComponent<P>

Represents the type of a function component. Can optionally receive a type argument that represents the props the component receives.

@seehttps://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/function_components React TypeScript Cheatsheet

@aliasfor FunctionComponent

@example

// With props:
type Props = { name: string }
const MyComponent: FC<Props> = (props) => {
return <div>{props.name}</div>
}

@example

// Without props:
const MyComponentWithoutProps: FC = () => {
return <div>MyComponentWithoutProps</div>
}

FC
} from 'react'
import {
function unstable_batchedUpdates<A, R>(callback: (a: A) => R, a: A): R (+1 overload)

React Native also implements unstable_batchedUpdates

unstable_batchedUpdates
as
function batchUpdates<A, R>(callback: (a: A) => R, a: A): R (+1 overload)

React Native also implements unstable_batchedUpdates

batchUpdates
,
class SafeAreaView

@deprecatedUse react-native-safe-area-context instead. This component is deprecated and will be removed in a future release.

SafeAreaView
,
class Text
Text
,
class View
View
} from 'react-native'
import {
const ListTodos: FC
ListTodos
} from './components/ListTodos.tsx'
import {
const NewTodo: FC
NewTodo
} from './components/NewTodo.tsx'
import {
const events: {
todoCreated: EventDef<"v1.TodoCreated", {
readonly id: string;
readonly text: string;
}, {
readonly id: string;
readonly text: string;
}, false>;
todoCompleted: EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: EventDef<...>;
uiStateSet: ClientDocumentTableDef.SetEventDefLike<...>;
}
events
,
const schema: FromInputSchema.DeriveSchema<{
events: {
todoCreated: EventDef<"v1.TodoCreated", {
readonly id: string;
readonly text: string;
}, {
readonly id: string;
readonly text: string;
}, false>;
todoCompleted: EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: EventDef<...>;
uiStateSet: ClientDocumentTableDef.SetEventDefLike<...>;
};
state: InternalState;
}>
schema
,
const tables: {
todos: TableDef<SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
columnType: "integer";
... 4 more ...;
autoIncrement: false;
};
}>, WithDefaults<...>, Schema<...>>;
uiState: ClientDocumentTableDef<...>;
}
tables
} from './livestore/schema.ts'
const
const storeId: "expo-todomvc"
storeId
= 'expo-todomvc'
const
const syncUrl: "https://example.org/sync"
syncUrl
= 'https://example.org/sync'
const
const adapter: Adapter
adapter
=
function makePersistedAdapter(options?: MakeDbOptions): Adapter
makePersistedAdapter
({
sync?: SyncOptions
sync
: {
backend?: SyncBackendConstructor<any, JsonValue>
backend
:
function makeWsSync(options: WsSyncOptions): SyncBackendConstructor<SyncMetadata>

Creates a sync backend that uses WebSocket to communicate with the sync backend.

@example

import { makeWsSync } from '@livestore/sync-cf/client'
const syncBackend = makeWsSync({ url: 'wss://sync.example.com' })

makeWsSync
({
WsSyncOptions.url: string

URL of the sync backend

The protocol can either http/https or ws/wss

url
:
const syncUrl: "https://example.org/sync"
syncUrl
}) },
})
export const
const Root: FC
Root
:
type FC<P = {}> = React.FunctionComponent<P>

Represents the type of a function component. Can optionally receive a type argument that represents the props the component receives.

@seehttps://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/function_components React TypeScript Cheatsheet

@aliasfor FunctionComponent

@example

// With props:
type Props = { name: string }
const MyComponent: FC<Props> = (props) => {
return <div>{props.name}</div>
}

@example

// Without props:
const MyComponentWithoutProps: FC = () => {
return <div>MyComponentWithoutProps</div>
}

FC
= () => (
<
class SafeAreaView

@deprecatedUse react-native-safe-area-context instead. This component is deprecated and will be removed in a future release.

SafeAreaView
style?: StyleProp<ViewStyle>
style
={{
FlexStyle.flex?: number | undefined
flex
: 1 }}>
<
const LiveStoreProvider: <TSyncPayloadSchema extends Schema<any> = Schema<JsonValue, JsonValue, never>>({ renderLoading, renderError, renderShutdown, otelOptions, children, schema, storeId, boot, adapter, batchUpdates, disableDevtools, signal, confirmUnsavedChanges, syncPayload, syncPayloadSchema, debug, }: LiveStoreProviderProps<TSyncPayloadSchema> & React.PropsWithChildren) => React.ReactNode
LiveStoreProvider
LiveStoreProviderProps<TSyncPayloadSchema extends Schema<any> = Schema<JsonValue, JsonValue, never>>.schema: LiveStoreSchema<DbSchema, EventDefRecord>
schema
={
const schema: FromInputSchema.DeriveSchema<{
events: {
todoCreated: EventDef<"v1.TodoCreated", {
readonly id: string;
readonly text: string;
}, {
readonly id: string;
readonly text: string;
}, false>;
todoCompleted: EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: EventDef<...>;
uiStateSet: ClientDocumentTableDef.SetEventDefLike<...>;
};
state: InternalState;
}>
schema
}
LiveStoreProviderProps<TSyncPayloadSchema extends Schema<any> = Schema<JsonValue, JsonValue, never>>.adapter: Adapter
adapter
={
const adapter: Adapter
adapter
}
LiveStoreProviderProps<TSyncPayloadSchema extends Schema<any> = Schema<JsonValue, JsonValue, never>>.storeId?: string

The storeId can be used to isolate multiple stores from each other. So it can be useful for multi-tenancy scenarios.

The storeId is also used for persistence.

Make sure to also configure storeId in LiveStore Devtools (e.g. in Vite plugin).

@default'default'

storeId
={
const storeId: "expo-todomvc"
storeId
}
LiveStoreProviderProps<Schema<JsonValue, JsonValue, never>>.batchUpdates: (run: () => void) => void

In order for LiveStore to apply multiple events in a single render, you need to pass the batchUpdates function from either react-dom or react-native.

// With React DOM
import { unstable_batchedUpdates as batchUpdates } from 'react-dom'
// With React Native
import { unstable_batchedUpdates as batchUpdates } from 'react-native'

batchUpdates
={
function batchUpdates<A, R>(callback: (a: A) => R, a: A): R (+1 overload)

React Native also implements unstable_batchedUpdates

batchUpdates
}
LiveStoreProviderProps<Schema<JsonValue, JsonValue, never>>.renderLoading?: (status: BootStatus) => React.ReactNode
renderLoading
={(
status: {
readonly stage: "loading";
} | {
readonly stage: "migrating";
readonly progress: {
readonly done: number;
readonly total: number;
};
} | {
readonly stage: "rehydrating";
readonly progress: {
readonly done: number;
readonly total: number;
};
} | {
readonly stage: "syncing";
readonly progress: {
readonly done: number;
readonly total: number;
};
} | {
readonly stage: "done";
}
status
) => <
class Text
Text
>Loading LiveStore ({
status: {
readonly stage: "loading";
} | {
readonly stage: "migrating";
readonly progress: {
readonly done: number;
readonly total: number;
};
} | {
readonly stage: "rehydrating";
readonly progress: {
readonly done: number;
readonly total: number;
};
} | {
readonly stage: "syncing";
readonly progress: {
readonly done: number;
readonly total: number;
};
} | {
readonly stage: "done";
}
status
.
stage: "loading" | "migrating" | "done" | "rehydrating" | "syncing"
stage
})...</
class Text
Text
>}
LiveStoreProviderProps<Schema<JsonValue, JsonValue, never>>.renderError?: (error: UnexpectedError | unknown) => React.ReactNode
renderError
={(
error: unknown
error
) => <
class Text
Text
>Error: {
var String: StringConstructor
(value?: any) => string

Allows manipulation and formatting of text strings and determination and location of substrings within strings.

String
(
error: unknown
error
)}</
class Text
Text
>}
LiveStoreProviderProps<Schema<JsonValue, JsonValue, never>>.renderShutdown?: (cause: IntentionalShutdownCause | StoreInterrupted | SyncError) => React.ReactNode
renderShutdown
={() => <
class Text
Text
>LiveStore shutdown</
class Text
Text
>}
LiveStoreProviderProps<Schema<JsonValue, JsonValue, never>>.boot?: (store: Store<LiveStoreSchema>, ctx: {
migrationsReport: MigrationsReport;
parentSpan: Span;
}) => void | Promise<void> | Effect<void, unknown, OtelTracer>
boot
={(
store: Store<LiveStoreSchema<DbSchema, EventDefRecord>, {}>
store
) => {
if (
store: Store<LiveStoreSchema<DbSchema, EventDefRecord>, {}>
store
.
Store<LiveStoreSchema<DbSchema, EventDefRecord>, {}>.query: <number>(query: Queryable<number> | {
query: string;
bindValues: Bindable;
schema?: Schema<number, number, never>;
}, options?: {
otelContext?: Context;
debugRefreshReason?: RefreshReason;
}) => number

Synchronously queries the database without creating a LiveQuery. This is useful for queries that don't need to be reactive.

Example: Query builder

const completedTodos = store.query(tables.todo.where({ complete: true }))

Example: Raw SQL query

const completedTodos = store.query({ query: 'SELECT * FROM todo WHERE complete = 1', bindValues: {} })

query
(
const tables: {
todos: TableDef<SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
columnType: "integer";
... 4 more ...;
autoIncrement: false;
};
}>, WithDefaults<...>, Schema<...>>;
uiState: ClientDocumentTableDef<...>;
}
tables
.
todos: TableDef<SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
columnType: "integer";
... 4 more ...;
autoIncrement: false;
};
}>, WithDefaults<...>, Schema<...>>
todos
.
count: () => QueryBuilder<number, TableDefBase<SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
columnType: "integer";
... 4 more ...;
autoIncrement: false;
};
}>, WithDefaults<...>>, "select" | ... 7 more ... | "row">

Example:

db.todos.count()
db.todos.count().where('completed', true)

count
()) === 0) {
store: Store<LiveStoreSchema<DbSchema, EventDefRecord>, {}>
store
.
Store<LiveStoreSchema<DbSchema, EventDefRecord>, {}>.commit: <readonly [{
name: "v1.TodoCreated";
args: {
readonly id: string;
readonly text: string;
};
}]>(list_0: {
name: "v1.TodoCreated";
args: {
readonly id: string;
readonly text: string;
};
}) => void (+3 overloads)
commit
(
const events: {
todoCreated: EventDef<"v1.TodoCreated", {
readonly id: string;
readonly text: string;
}, {
readonly id: string;
readonly text: string;
}, false>;
todoCompleted: EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: EventDef<...>;
uiStateSet: ClientDocumentTableDef.SetEventDefLike<...>;
}
events
.
todoCreated: (args: {
readonly id: string;
readonly text: string;
}) => {
name: "v1.TodoCreated";
args: {
readonly id: string;
readonly text: string;
};
}

Helper function to construct a partial event

todoCreated
({
id: string
id
:
var crypto: Crypto
crypto
.
Crypto.randomUUID(): `${string}-${string}-${string}-${string}-${string}` (+1 overload)
randomUUID
(),
text: string
text
: 'Make coffee' }))
}
}}
>
<
class View
View
style?: StyleProp<ViewStyle>
style
={{
FlexStyle.flex?: number | undefined
flex
: 1,
FlexStyle.gap?: string | number | undefined
gap
: 24,
FlexStyle.padding?: DimensionValue | undefined
padding
: 24 }}>
<
const NewTodo: FC
NewTodo
/>
<
const ListTodos: FC
ListTodos
/>
</
class View
View
>
</
const LiveStoreProvider: <TSyncPayloadSchema extends Schema<any> = Schema<JsonValue, JsonValue, never>>({ renderLoading, renderError, renderShutdown, otelOptions, children, schema, storeId, boot, adapter, batchUpdates, disableDevtools, signal, confirmUnsavedChanges, syncPayload, syncPayloadSchema, debug, }: LiveStoreProviderProps<TSyncPayloadSchema> & React.PropsWithChildren) => React.ReactNode
LiveStoreProvider
>
<
function StatusBar({ style, hideTransitionAnimation, translucent, backgroundColor: backgroundColorProp, ...props }: StatusBarProps): React.JSX.Element

A component that allows you to configure your status bar without directly calling imperative methods like setBarStyle.

You will likely have multiple StatusBar components mounted in the same app at the same time. For example, if you have multiple screens in your app, you may end up using one per screen. The props of each StatusBar component will be merged in the order that they were mounted. This component is built on top of the StatusBar component exported from React Native, and it provides defaults that work better for Expo users.

StatusBar
style?: StatusBarStyle

Sets the color of the status bar text. Default value is "auto" which picks the appropriate value according to the active color scheme, eg: if your app is dark mode, the style will be "light".

@default'auto'

style
="auto" />
</
class SafeAreaView

@deprecatedUse react-native-safe-area-context instead. This component is deprecated and will be removed in a future release.

SafeAreaView
>
)

After wrapping your app with the LiveStoreProvider, you can use the useStore hook from any component to commit events.

Here’s an example:

import {
const useQuery: <TQueryable extends Queryable<any>>(queryable: TQueryable, options?: {
store?: Store;
}) => Queryable.Result<TQueryable>

Returns the result of a query and subscribes to future updates.

Example:

const App = () => {
const todos = useQuery(queryDb(tables.todos.query.where({ complete: true })))
return <div>{todos.map((todo) => <div key={todo.id}>{todo.title}</div>)}</div>
}

useQuery
,
const useStore: (options?: {
store?: Store;
}) => {
store: Store & ReactApi;
}
useStore
} from '@livestore/react'
import type {
type FC<P = {}> = React.FunctionComponent<P>

Represents the type of a function component. Can optionally receive a type argument that represents the props the component receives.

@seehttps://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/function_components React TypeScript Cheatsheet

@aliasfor FunctionComponent

@example

// With props:
type Props = { name: string }
const MyComponent: FC<Props> = (props) => {
return <div>{props.name}</div>
}

@example

// Without props:
const MyComponentWithoutProps: FC = () => {
return <div>MyComponentWithoutProps</div>
}

FC
} from 'react'
import {
class Button
Button
,
class TextInput
TextInput
,
class View
View
} from 'react-native'
import {
const uiState$: LiveQueryDef<{
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
}, "def">
uiState$
} from '../livestore/queries.ts'
import {
const events: {
todoCreated: EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>;
todoCompleted: EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: EventDef<...>;
uiStateSet: ClientDocumentTableDef.SetEventDefLike<...>;
}
events
} from '../livestore/schema.ts'
export const
const NewTodo: FC
NewTodo
:
type FC<P = {}> = React.FunctionComponent<P>

Represents the type of a function component. Can optionally receive a type argument that represents the props the component receives.

@seehttps://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/function_components React TypeScript Cheatsheet

@aliasfor FunctionComponent

@example

// With props:
type Props = { name: string }
const MyComponent: FC<Props> = (props) => {
return <div>{props.name}</div>
}

@example

// Without props:
const MyComponentWithoutProps: FC = () => {
return <div>MyComponentWithoutProps</div>
}

FC
= () => {
const {
const store: Store<LiveStoreSchema.Any, {}> & ReactApi
store
} =
function useStore(options?: {
store?: Store;
}): {
store: Store & ReactApi;
}
useStore
()
const {
const newTodoText: string
newTodoText
} =
useQuery<LiveQueryDef<{
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
}, "def">>(queryable: LiveQueryDef<{
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
}, "def">, options?: {
store?: Store;
}): {
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
}

Returns the result of a query and subscribes to future updates.

Example:

const App = () => {
const todos = useQuery(queryDb(tables.todos.query.where({ complete: true })))
return <div>{todos.map((todo) => <div key={todo.id}>{todo.title}</div>)}</div>
}

useQuery
(
const uiState$: LiveQueryDef<{
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
}, "def">
uiState$
)
const
const updateText: (text: string) => void
updateText
= (
text: string
text
: string) =>
const store: Store<LiveStoreSchema.Any, {}> & ReactApi
store
.
Store<LiveStoreSchema<TDbSchema extends DbSchema = DbSchema, TEventsDefRecord extends EventDefRecord = EventDefRecord>.Any, {}>.commit: <readonly [{
name: "uiStateSet";
args: {
id: string;
value: {
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
};
};
}]>(list_0: {
name: "uiStateSet";
args: {
id: string;
value: {
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
};
};
}) => void (+3 overloads)
commit
(
const events: {
todoCreated: EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>;
todoCompleted: EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: EventDef<...>;
uiStateSet: ClientDocumentTableDef.SetEventDefLike<...>;
}
events
.
uiStateSet: (args: Partial<{
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
}>, id?: string | SessionIdSymbol) => {
name: "uiStateSet";
args: {
id: string;
value: {
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
};
};
}
uiStateSet
({
newTodoText?: string
newTodoText
:
text: string
text
}))
const
const createTodo: () => void
createTodo
= () =>
const store: Store<LiveStoreSchema.Any, {}> & ReactApi
store
.
Store<LiveStoreSchema<TDbSchema extends DbSchema = DbSchema, TEventsDefRecord extends EventDefRecord = EventDefRecord>.Any, {}>.commit: <readonly [{
name: "v1.TodoCreated";
args: {
readonly text: string;
readonly id: string;
};
}, {
name: "uiStateSet";
args: {
id: string;
value: {
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
};
};
}]>(list_0: {
name: "v1.TodoCreated";
args: {
readonly text: string;
readonly id: string;
};
}, list_1: {
name: "uiStateSet";
args: {
id: string;
value: {
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
};
};
}) => void (+3 overloads)
commit
(
const events: {
todoCreated: EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>;
todoCompleted: EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: EventDef<...>;
uiStateSet: ClientDocumentTableDef.SetEventDefLike<...>;
}
events
.
todoCreated: (args: {
readonly text: string;
readonly id: string;
}) => {
name: "v1.TodoCreated";
args: {
readonly text: string;
readonly id: string;
};
}

Helper function to construct a partial event

todoCreated
({
id: string
id
:
var crypto: Crypto
crypto
.
Crypto.randomUUID(): `${string}-${string}-${string}-${string}-${string}` (+1 overload)
randomUUID
(),
text: string
text
:
const newTodoText: string
newTodoText
}),
const events: {
todoCreated: EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>;
todoCompleted: EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: EventDef<...>;
uiStateSet: ClientDocumentTableDef.SetEventDefLike<...>;
}
events
.
uiStateSet: (args: Partial<{
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
}>, id?: string | SessionIdSymbol) => {
name: "uiStateSet";
args: {
id: string;
value: {
readonly filter: "completed" | "all" | "active";
readonly newTodoText: string;
};
};
}
uiStateSet
({
newTodoText?: string
newTodoText
: '' }),
)
const
const addSampleTodos: () => void
addSampleTodos
= () => {
const
const todos: {
id: `${string}-${string}-${string}-${string}-${string}`;
text: string;
}[]
todos
=
var Array: ArrayConstructor
Array
.
ArrayConstructor.from<unknown, {
id: `${string}-${string}-${string}-${string}-${string}`;
text: string;
}>(iterable: Iterable<unknown> | ArrayLike<unknown>, mapfn: (v: unknown, k: number) => {
id: `${string}-${string}-${string}-${string}-${string}`;
text: string;
}, thisArg?: any): {
id: `${string}-${string}-${string}-${string}-${string}`;
text: string;
}[] (+3 overloads)

Creates an array from an iterable object.

@paramiterable An iterable object to convert to an array.

@parammapfn A mapping function to call on every element of the array.

@paramthisArg Value of 'this' used to invoke the mapfn.

from
({
ArrayLike<T>.length: number
length
: 5 }, (
_: unknown
_
,
index: number
index
) => ({
id: `${string}-${string}-${string}-${string}-${string}`
id
:
var crypto: Crypto
crypto
.
Crypto.randomUUID(): `${string}-${string}-${string}-${string}-${string}` (+1 overload)
randomUUID
(),
text: string
text
: `Todo ${
index: number
index
+ 1}`,
}))
const store: Store<LiveStoreSchema.Any, {}> & ReactApi
store
.
Store<LiveStoreSchema<TDbSchema extends DbSchema = DbSchema, TEventsDefRecord extends EventDefRecord = EventDefRecord>.Any, {}>.commit: <{
name: "v1.TodoCreated";
args: {
readonly text: string;
readonly id: string;
};
}[]>(...list: {
name: "v1.TodoCreated";
args: {
readonly text: string;
readonly id: string;
};
}[]) => void (+3 overloads)
commit
(...
const todos: {
id: `${string}-${string}-${string}-${string}-${string}`;
text: string;
}[]
todos
.
Array<{ id: `${string}-${string}-${string}-${string}-${string}`; text: string; }>.map<{
name: "v1.TodoCreated";
args: {
readonly text: string;
readonly id: string;
};
}>(callbackfn: (value: {
id: `${string}-${string}-${string}-${string}-${string}`;
text: string;
}, index: number, array: {
id: `${string}-${string}-${string}-${string}-${string}`;
text: string;
}[]) => {
name: "v1.TodoCreated";
args: {
readonly text: string;
readonly id: string;
};
}, thisArg?: any): {
name: "v1.TodoCreated";
args: {
readonly text: string;
readonly id: string;
};
}[]

Calls a defined callback function on each element of an array, and returns an array that contains the results.

@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.

@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.

map
((
todo: {
id: `${string}-${string}-${string}-${string}-${string}`;
text: string;
}
todo
) =>
const events: {
todoCreated: EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>;
todoCompleted: EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: EventDef<...>;
uiStateSet: ClientDocumentTableDef.SetEventDefLike<...>;
}
events
.
todoCreated: (args: {
readonly text: string;
readonly id: string;
}) => {
name: "v1.TodoCreated";
args: {
readonly text: string;
readonly id: string;
};
}

Helper function to construct a partial event

todoCreated
(
todo: {
id: `${string}-${string}-${string}-${string}-${string}`;
text: string;
}
todo
)))
}
return (
<
class View
View
style?: StyleProp<ViewStyle>
style
={{
FlexStyle.gap?: string | number | undefined
gap
: 12 }}>
<
class TextInput
TextInput
value?: string | undefined

The value to show for the text input. TextInput is a controlled component, which means the native value will be forced to match this value prop if provided. For most uses this works great, but in some cases this may cause flickering - one common cause is preventing edits by keeping value the same. In addition to simply setting the same value, either set editable={false}, or set/update maxLength to prevent unwanted edits without flicker.

value
={
const newTodoText: string
newTodoText
}
onChangeText?: ((text: string) => void) | undefined

Callback that is called when the text input's text changes. Changed text is passed as an argument to the callback handler.

onChangeText
={
const updateText: (text: string) => void
updateText
}
placeholder?: string | undefined

The string that will be rendered before text input has been entered

placeholder
="What needs to be done?" />
<
class Button
Button
title: string

Text to display inside the button. On Android the given title will be converted to the uppercased form.

title
="Add todo"
onPress?: ((event: GestureResponderEvent) => void) | undefined

Called when the touch is released, but not if cancelled (e.g. by a scroll that steals the responder lock).

onPress
={
const createTodo: () => void
createTodo
} />
<
class Button
Button
title: string

Text to display inside the button. On Android the given title will be converted to the uppercased form.

title
="Add sample todos"
onPress?: ((event: GestureResponderEvent) => void) | undefined

Called when the touch is released, but not if cancelled (e.g. by a scroll that steals the responder lock).

onPress
={
const addSampleTodos: () => void
addSampleTodos
} />
</
class View
View
>
)
}

To retrieve data from the database, first define a query using queryDb from @livestore/livestore. Then, execute the query with the useQuery hook from @livestore/react.

Consider abstracting queries into a separate file to keep your code organized, though you can also define them directly within components if preferred.

Here’s an example:

import {
const useQuery: <TQueryable extends Queryable<any>>(queryable: TQueryable, options?: {
store?: Store;
}) => Queryable.Result<TQueryable>

Returns the result of a query and subscribes to future updates.

Example:

const App = () => {
const todos = useQuery(queryDb(tables.todos.query.where({ complete: true })))
return <div>{todos.map((todo) => <div key={todo.id}>{todo.title}</div>)}</div>
}

useQuery
,
const useStore: (options?: {
store?: Store;
}) => {
store: Store & ReactApi;
}
useStore
} from '@livestore/react'
import { type
type FC<P = {}> = React.FunctionComponent<P>

Represents the type of a function component. Can optionally receive a type argument that represents the props the component receives.

@seehttps://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/function_components React TypeScript Cheatsheet

@aliasfor FunctionComponent

@example

// With props:
type Props = { name: string }
const MyComponent: FC<Props> = (props) => {
return <div>{props.name}</div>
}

@example

// Without props:
const MyComponentWithoutProps: FC = () => {
return <div>MyComponentWithoutProps</div>
}

FC
,
function useCallback<T extends Function>(callback: T, deps: React.DependencyList): T

useCallback will return a memoized version of the callback that only changes if one of the inputs has changed.

useCallback
} from 'react'
import {
class Button
Button
,
class ScrollView
ScrollView
,
class Text
Text
,
class View
View
} from 'react-native'
import {
const visibleTodos$: LiveQueryDef<readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}[], "def">
visibleTodos$
} from '../livestore/queries.ts'
import {
const events: {
todoCreated: EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>;
todoCompleted: EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: EventDef<...>;
uiStateSet: ClientDocumentTableDef.SetEventDefLike<...>;
}
events
, type
const tables: {
todos: TableDef<SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
columnType: "integer";
... 4 more ...;
autoIncrement: false;
};
}>, WithDefaults<...>, Schema<...>>;
uiState: ClientDocumentTableDef<...>;
}
tables
} from '../livestore/schema.ts'
export const
const ListTodos: FC
ListTodos
:
type FC<P = {}> = React.FunctionComponent<P>

Represents the type of a function component. Can optionally receive a type argument that represents the props the component receives.

@seehttps://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/function_components React TypeScript Cheatsheet

@aliasfor FunctionComponent

@example

// With props:
type Props = { name: string }
const MyComponent: FC<Props> = (props) => {
return <div>{props.name}</div>
}

@example

// Without props:
const MyComponentWithoutProps: FC = () => {
return <div>MyComponentWithoutProps</div>
}

FC
= () => {
const {
const store: Store<LiveStoreSchema.Any, {}> & ReactApi
store
} =
function useStore(options?: {
store?: Store;
}): {
store: Store & ReactApi;
}
useStore
()
const
const todos: readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}[]
todos
=
useQuery<LiveQueryDef<readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}[], "def">>(queryable: LiveQueryDef<readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}[], "def">, options?: {
store?: Store;
}): readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}[]

Returns the result of a query and subscribes to future updates.

Example:

const App = () => {
const todos = useQuery(queryDb(tables.todos.query.where({ complete: true })))
return <div>{todos.map((todo) => <div key={todo.id}>{todo.title}</div>)}</div>
}

useQuery
(
const visibleTodos$: LiveQueryDef<readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}[], "def">
visibleTodos$
)
const
const toggleTodo: ({ id, completed }: typeof tables.todos.Type) => void
toggleTodo
=
useCallback<({ id, completed }: typeof tables.todos.Type) => void>(callback: ({ id, completed }: typeof tables.todos.Type) => void, deps: React.DependencyList): ({ id, completed }: typeof tables.todos.Type) => void

useCallback will return a memoized version of the callback that only changes if one of the inputs has changed.

useCallback
(
({
id: string
id
,
completed: boolean
completed
}: typeof
const tables: {
todos: TableDef<SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
columnType: "integer";
... 4 more ...;
autoIncrement: false;
};
}>, WithDefaults<...>, Schema<...>>;
uiState: ClientDocumentTableDef<...>;
}
tables
.
todos: TableDef<SqliteTableDefForInput<"todos", {
readonly id: {
columnType: "text";
schema: Schema<string, string, never>;
default: None<never>;
nullable: false;
primaryKey: true;
autoIncrement: false;
};
readonly text: {
columnType: "text";
schema: Schema<string, string, never>;
default: Some<"">;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly deletedAt: {
columnType: "integer";
... 4 more ...;
autoIncrement: false;
};
}>, WithDefaults<...>, Schema<...>>
todos
.
type Type: {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}
Type
) => {
const store: Store<LiveStoreSchema.Any, {}> & ReactApi
store
.
Store<LiveStoreSchema<TDbSchema extends DbSchema = DbSchema, TEventsDefRecord extends EventDefRecord = EventDefRecord>.Any, {}>.commit: <readonly [{
name: "v1.TodoUncompleted";
args: {
readonly id: string;
};
} | {
name: "v1.TodoCompleted";
args: {
readonly id: string;
};
}]>(list_0: {
name: "v1.TodoUncompleted";
args: {
readonly id: string;
};
} | {
name: "v1.TodoCompleted";
args: {
readonly id: string;
};
}) => void (+3 overloads)
commit
(
completed: boolean
completed
?
const events: {
todoCreated: EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>;
todoCompleted: EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: EventDef<...>;
uiStateSet: ClientDocumentTableDef.SetEventDefLike<...>;
}
events
.
todoUncompleted: (args: {
readonly id: string;
}) => {
name: "v1.TodoUncompleted";
args: {
readonly id: string;
};
}

Helper function to construct a partial event

todoUncompleted
({
id: string
id
}) :
const events: {
todoCreated: EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>;
todoCompleted: EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: EventDef<...>;
uiStateSet: ClientDocumentTableDef.SetEventDefLike<...>;
}
events
.
todoCompleted: (args: {
readonly id: string;
}) => {
name: "v1.TodoCompleted";
args: {
readonly id: string;
};
}

Helper function to construct a partial event

todoCompleted
({
id: string
id
}))
},
[
const store: Store<LiveStoreSchema.Any, {}> & ReactApi
store
],
)
const
const clearCompleted: () => void
clearCompleted
= () =>
const store: Store<LiveStoreSchema.Any, {}> & ReactApi
store
.
Store<LiveStoreSchema<TDbSchema extends DbSchema = DbSchema, TEventsDefRecord extends EventDefRecord = EventDefRecord>.Any, {}>.commit: <readonly [{
name: "v1.TodoClearedCompleted";
args: {
readonly deletedAt: Date;
};
}]>(list_0: {
name: "v1.TodoClearedCompleted";
args: {
readonly deletedAt: Date;
};
}) => void (+3 overloads)
commit
(
const events: {
todoCreated: EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>;
todoCompleted: EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: EventDef<...>;
uiStateSet: ClientDocumentTableDef.SetEventDefLike<...>;
}
events
.
todoClearedCompleted: (args: {
readonly deletedAt: Date;
}) => {
name: "v1.TodoClearedCompleted";
args: {
readonly deletedAt: Date;
};
}

Helper function to construct a partial event

todoClearedCompleted
({
deletedAt: Date
deletedAt
: new
var Date: DateConstructor
new () => Date (+3 overloads)
Date
() }))
return (
<
class View
View
style?: StyleProp<ViewStyle>
style
={{
FlexStyle.flex?: number | undefined
flex
: 1,
FlexStyle.gap?: string | number | undefined
gap
: 16 }}>
<
class ScrollView
ScrollView
contentContainerStyle?: StyleProp<ViewStyle>

These styles will be applied to the scroll view content container which wraps all of the child views. Example:

return ( ); ... const styles = StyleSheet.create({ contentContainer: { paddingVertical: 20 } });

contentContainerStyle
={{
FlexStyle.gap?: string | number | undefined
gap
: 12 }}>
{
const todos: readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}[]
todos
.
ReadonlyArray<{ readonly id: string; readonly text: string; readonly completed: boolean; readonly deletedAt: Date | null; }>.map<JSX.Element>(callbackfn: (value: {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}, index: number, array: readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}[]) => JSX.Element, thisArg?: any): JSX.Element[]

Calls a defined callback function on each element of an array, and returns an array that contains the results.

@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.

@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.

map
((
todo: {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}
todo
) => (
<
class View
View
React.Attributes.key?: React.Key | null | undefined
key
={
todo: {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}
todo
.
id: string
id
}
style?: StyleProp<ViewStyle>
style
={{
ViewStyle.borderRadius?: string | AnimatableNumericValue | undefined
borderRadius
: 12,
ViewStyle.borderColor?: ColorValue | undefined
borderColor
: '#d4d4d8',
FlexStyle.borderWidth?: number | undefined
borderWidth
: 1,
FlexStyle.padding?: DimensionValue | undefined
padding
: 16,
FlexStyle.gap?: string | number | undefined
gap
: 8,
}}
>
<
class Text
Text
style?: StyleProp<TextStyle>
style
={{
TextStyle.fontSize?: number | undefined
fontSize
: 16,
TextStyle.fontWeight?: "normal" | "bold" | "100" | "200" | "300" | "400" | "500" | "600" | "700" | "800" | "900" | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | "ultralight" | "thin" | "light" | "medium" | "regular" | "semibold" | "condensedBold" | "condensed" | "heavy" | "black" | undefined

Specifies font weight. The values 'normal' and 'bold' are supported for most fonts. Not all fonts have a variant for each of the numeric values, in that case the closest one is chosen.

fontWeight
: '600' }}>{
todo: {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}
todo
.
text: string
text
}</
class Text
Text
>
<
class Text
Text
>{
todo: {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}
todo
.
completed: boolean
completed
? 'Completed' : 'Pending'}</
class Text
Text
>
<
class View
View
style?: StyleProp<ViewStyle>
style
={{
FlexStyle.flexDirection?: "row" | "column" | "row-reverse" | "column-reverse" | undefined
flexDirection
: 'row',
FlexStyle.gap?: string | number | undefined
gap
: 12 }}>
<
class Button
Button
title: string

Text to display inside the button. On Android the given title will be converted to the uppercased form.

title
={
todo: {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}
todo
.
completed: boolean
completed
? 'Mark pending' : 'Mark done'}
onPress?: ((event: GestureResponderEvent) => void) | undefined

Called when the touch is released, but not if cancelled (e.g. by a scroll that steals the responder lock).

onPress
={() =>
const toggleTodo: ({ id, completed }: typeof tables.todos.Type) => void
toggleTodo
(
todo: {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}
todo
)} />
<
class Button
Button
title: string

Text to display inside the button. On Android the given title will be converted to the uppercased form.

title
="Delete"
onPress?: ((event: GestureResponderEvent) => void) | undefined

Called when the touch is released, but not if cancelled (e.g. by a scroll that steals the responder lock).

onPress
={() =>
const store: Store<LiveStoreSchema.Any, {}> & ReactApi
store
.
Store<LiveStoreSchema<TDbSchema extends DbSchema = DbSchema, TEventsDefRecord extends EventDefRecord = EventDefRecord>.Any, {}>.commit: <readonly [{
name: "v1.TodoDeleted";
args: {
readonly id: string;
readonly deletedAt: Date;
};
}]>(list_0: {
name: "v1.TodoDeleted";
args: {
readonly id: string;
readonly deletedAt: Date;
};
}) => void (+3 overloads)
commit
(
const events: {
todoCreated: EventDef<"v1.TodoCreated", {
readonly text: string;
readonly id: string;
}, {
readonly text: string;
readonly id: string;
}, false>;
todoCompleted: EventDef<"v1.TodoCompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoUncompleted: EventDef<"v1.TodoUncompleted", {
readonly id: string;
}, {
readonly id: string;
}, false>;
todoDeleted: EventDef<"v1.TodoDeleted", {
readonly id: string;
readonly deletedAt: Date;
}, {
readonly id: string;
readonly deletedAt: string;
}, false>;
todoClearedCompleted: EventDef<...>;
uiStateSet: ClientDocumentTableDef.SetEventDefLike<...>;
}
events
.
todoDeleted: (args: {
readonly id: string;
readonly deletedAt: Date;
}) => {
name: "v1.TodoDeleted";
args: {
readonly id: string;
readonly deletedAt: Date;
};
}

Helper function to construct a partial event

todoDeleted
({
id: string
id
:
todo: {
readonly id: string;
readonly text: string;
readonly completed: boolean;
readonly deletedAt: Date | null;
}
todo
.
id: string
id
,
deletedAt: Date
deletedAt
: new
var Date: DateConstructor
new () => Date (+3 overloads)
Date
() }))}
/>
</
class View
View
>
</
class View
View
>
))}
</
class ScrollView
ScrollView
>
<
class Button
Button
title: string

Text to display inside the button. On Android the given title will be converted to the uppercased form.

title
="Clear completed"
onPress?: ((event: GestureResponderEvent) => void) | undefined

Called when the touch is released, but not if cancelled (e.g. by a scroll that steals the responder lock).

onPress
={
const clearCompleted: () => void
clearCompleted
} />
</
class View
View
>
)
}

To open the devtools, run the app and from your terminal press shift + m, then select LiveStore Devtools and press Enter.

Expo Terminal Screenshot

This will open the devtools in a new tab in your default browser.

Devtools Browser Screenshot

Use the devtools to inspect the state of your LiveStore database, execute events, track performance, and more.

To open the database in Finder, run the following command in your terminal:

Terminal window
open $(find $(xcrun simctl get_app_container booted host.exp.Exponent data) -path "*/Documents/ExponentExperienceData/*livestore-expo*" -print -quit)/SQLite

For development builds, the app SQLite database is stored in the app’s Library directory.

Example: /Users/<USERNAME>/Library/Developer/CoreSimulator/Devices/<DEVICE_ID>/data/Containers/Data/Application/<APP_ID>/Documents/SQLite/app.db

To open the database in Finder, run the following command in your terminal:

Terminal window
open $(xcrun simctl get_app_container booted [APP_BUNDLE_ID] data)/Documents/SQLite

Replace [APP_BUNDLE_ID] with your app’s bundle ID. e.g. dev.livestore.livestore-expo.

  • LiveStore doesn’t yet support Expo Web (see #130)