Skip to content

React integration for LiveStore

While LiveStore is framework agnostic, the @livestore/react package provides a first-class integration with React.

  • High performance
  • Fine-grained reactivity (using LiveStore’s signals-based reactivity system)
  • Instant, synchronous query results (without the need for useEffect and isLoading checks)
  • Transactional state transitions (via batchUpdates)
  • Also supports Expo / React Native via @livestore/adapter-expo

In order to use LiveStore with React, you need to wrap your application in a LiveStoreProvider.

import {
const makeInMemoryAdapter: (options?: InMemoryAdapterOptions) => Adapter

Create a web-only in-memory LiveStore adapter.

  • Runs entirely in memory: fast, zero I/O, great for tests, sandboxes, or ephemeral sessions.
  • Works across browser execution contexts: Window, WebWorker, SharedWorker, and ServiceWorker.
  • DevTools: to inspect this adapter from the browser DevTools, provide a sharedWorker in options.devtools. (The shared worker is used to bridge the DevTools UI to the running session.)
  • No persistence support: nothing is written to OPFS/IndexedDB/localStorage. importSnapshot can bootstrap initial state only; subsequent changes are not persisted anywhere.

makeInMemoryAdapter
} from '@livestore/adapter-web'
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 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
,
type ReactNode = string | number | bigint | boolean | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<ReactNode> | React.ReactPortal | Promise<AwaitedReactNode> | null | undefined

Represents all of the things React can render.

Where

ReactElement

only represents JSX, ReactNode represents everything that can be rendered.

@seehttps://react-typescript-cheatsheet.netlify.app/docs/react-types/reactnode/ React TypeScript Cheatsheet

@example

// Typing children
type Props = { children: ReactNode }
const Component = ({ children }: Props) => <div>{children}</div>
<Component>hello</Component>

@example

// Typing a custom element
type Props = { customElement: ReactNode }
const Component = ({ customElement }: Props) => <div>{customElement}</div>
<Component customElement={<div>hello</div>} />

ReactNode
} from 'react'
import {
function unstable_batchedUpdates<A, R>(callback: (a: A) => R, a: A): R (+1 overload)
unstable_batchedUpdates
as
function batchUpdates<A, R>(callback: (a: A) => R, a: A): R (+1 overload)
batchUpdates
} from 'react-dom'
import {
const schema: FromInputSchema.DeriveSchema<{
events: {
readonly todoCreated: EventDef<"v1.TodoCreated", {
readonly id: string;
readonly text: string;
}, {
readonly id: string;
readonly text: string;
}, false>;
};
state: InternalState;
}>
schema
} from './schema.ts'
const
const adapter: Adapter
adapter
=
function makeInMemoryAdapter(options?: InMemoryAdapterOptions): Adapter

Create a web-only in-memory LiveStore adapter.

  • Runs entirely in memory: fast, zero I/O, great for tests, sandboxes, or ephemeral sessions.
  • Works across browser execution contexts: Window, WebWorker, SharedWorker, and ServiceWorker.
  • DevTools: to inspect this adapter from the browser DevTools, provide a sharedWorker in options.devtools. (The shared worker is used to bridge the DevTools UI to the running session.)
  • No persistence support: nothing is written to OPFS/IndexedDB/localStorage. importSnapshot can bootstrap initial state only; subsequent changes are not persisted anywhere.

makeInMemoryAdapter
()
export const
const Root: FC<{
children: ReactNode;
}>
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
<{
children: ReactNode
children
:
type ReactNode = string | number | bigint | boolean | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<ReactNode> | React.ReactPortal | Promise<AwaitedReactNode> | null | undefined

Represents all of the things React can render.

Where

ReactElement

only represents JSX, ReactNode represents everything that can be rendered.

@seehttps://react-typescript-cheatsheet.netlify.app/docs/react-types/reactnode/ React TypeScript Cheatsheet

@example

// Typing children
type Props = { children: ReactNode }
const Component = ({ children }: Props) => <div>{children}</div>
<Component>hello</Component>

@example

// Typing a custom element
type Props = { customElement: ReactNode }
const Component = ({ customElement }: Props) => <div>{customElement}</div>
<Component customElement={<div>hello</div>} />

ReactNode
}> = ({
children: ReactNode
children
}) => (
<
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: {
readonly todoCreated: EventDef<"v1.TodoCreated", {
readonly id: string;
readonly text: string;
}, {
readonly id: string;
readonly text: string;
}, false>;
};
state: InternalState;
}>
schema
}
LiveStoreProviderProps<TSyncPayloadSchema extends Schema<any> = Schema<JsonValue, JsonValue, never>>.adapter: Adapter
adapter
={
const adapter: Adapter
adapter
}
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)
batchUpdates
}>
{
children: ReactNode
children
}
</
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
>
)

For scenarios where you have an existing store instance, you can manually create a LiveStoreContext.Provider:

import type {
class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TContext = {}>
Store
} from '@livestore/livestore'
import {
const LiveStoreContext: React.Context<{
stage: "running";
store: LiveStoreContextRunning["store"] & ReactApi;
} | undefined>
LiveStoreContext
, type
type ReactApi = {
useQuery: typeof useQuery;
useClientDocument: typeof useClientDocument;
}
ReactApi
} 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
,
type ReactNode = string | number | bigint | boolean | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<ReactNode> | React.ReactPortal | Promise<AwaitedReactNode> | null | undefined

Represents all of the things React can render.

Where

ReactElement

only represents JSX, ReactNode represents everything that can be rendered.

@seehttps://react-typescript-cheatsheet.netlify.app/docs/react-types/reactnode/ React TypeScript Cheatsheet

@example

// Typing children
type Props = { children: ReactNode }
const Component = ({ children }: Props) => <div>{children}</div>
<Component>hello</Component>

@example

// Typing a custom element
type Props = { customElement: ReactNode }
const Component = ({ customElement }: Props) => <div>{customElement}</div>
<Component customElement={<div>hello</div>} />

ReactNode
} from 'react'
declare const
const store: Store<LiveStoreSchema.Any, {}> & ReactApi
store
:
class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TContext = {}>
Store
&
type ReactApi = {
useQuery: typeof useQuery;
useClientDocument: typeof useClientDocument;
}
ReactApi
export const
const Root: FC<{
children: ReactNode;
}>
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
<{
children: ReactNode
children
:
type ReactNode = string | number | bigint | boolean | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<ReactNode> | React.ReactPortal | Promise<AwaitedReactNode> | null | undefined

Represents all of the things React can render.

Where

ReactElement

only represents JSX, ReactNode represents everything that can be rendered.

@seehttps://react-typescript-cheatsheet.netlify.app/docs/react-types/reactnode/ React TypeScript Cheatsheet

@example

// Typing children
type Props = { children: ReactNode }
const Component = ({ children }: Props) => <div>{children}</div>
<Component>hello</Component>

@example

// Typing a custom element
type Props = { customElement: ReactNode }
const Component = ({ customElement }: Props) => <div>{customElement}</div>
<Component customElement={<div>hello</div>} />

ReactNode
}> = ({
children: ReactNode
children
}) => (
<
const LiveStoreContext: React.Context<{
stage: "running";
store: LiveStoreContextRunning["store"] & ReactApi;
} | undefined>
LiveStoreContext
.
React.Context<{ stage: "running"; store: LiveStoreContextRunning["store"] & ReactApi; } | undefined>.Provider: React.Provider<{
stage: "running";
store: LiveStoreContextRunning["store"] & ReactApi;
} | undefined>
Provider
React.ProviderProps<{ stage: "running"; store: LiveStoreContextRunning["store"] & ReactApi; } | undefined>.value: {
stage: "running";
store: LiveStoreContextRunning["store"] & ReactApi;
} | undefined
value
={{
stage: "running"
stage
: 'running',
store: Store<LiveStoreSchema.Any, {}> & ReactApi
store
}}>{
children: ReactNode
children
}</
const LiveStoreContext: React.Context<{
stage: "running";
store: LiveStoreContextRunning["store"] & ReactApi;
} | undefined>
LiveStoreContext
.
React.Context<{ stage: "running"; store: LiveStoreContextRunning["store"] & ReactApi; } | undefined>.Provider: React.Provider<{
stage: "running";
store: LiveStoreContextRunning["store"] & ReactApi;
} | undefined>
Provider
>
)
import {
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 {
function useEffect(effect: React.EffectCallback, deps?: React.DependencyList): void

Accepts a function that contains imperative, possibly effectful code.

@parameffect Imperative function that can return a cleanup function

@paramdeps If present, effect will only activate if the values in the list change.

@version16.8.0

@seehttps://react.dev/reference/react/useEffect

useEffect
} from 'react'
import {
const events: {
readonly todoCreated: EventDef<"v1.TodoCreated", {
readonly id: string;
readonly text: string;
}, {
readonly id: string;
readonly text: string;
}, false>;
}
events
} from './schema.ts'
export const
const MyComponent: FC
MyComponent
:
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
()
function useEffect(effect: React.EffectCallback, deps?: React.DependencyList): void

Accepts a function that contains imperative, possibly effectful code.

@parameffect Imperative function that can return a cleanup function

@paramdeps If present, effect will only activate if the values in the list change.

@version16.8.0

@seehttps://react.dev/reference/react/useEffect

useEffect
(() => {
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 id: string;
readonly text: string;
};
}]>(list_0: {
name: "v1.TodoCreated";
args: {
readonly id: string;
readonly text: string;
};
}) => void (+3 overloads)
commit
(
const events: {
readonly todoCreated: EventDef<"v1.TodoCreated", {
readonly id: string;
readonly text: string;
}, {
readonly id: string;
readonly text: string;
}, false>;
}
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
: '1',
text: string
text
: 'Hello, world!' }))
}, [
const store: Store<LiveStoreSchema.Any, {}> & ReactApi
store
])
return <
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>...</
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
}
import {
const queryDb: {
<TResultSchema, TResult = TResultSchema>(queryInput: QueryInputRaw<TResultSchema, ReadonlyArray<any>> | QueryBuilder<TResultSchema, any, any>, options?: {
map?: (rows: TResultSchema) => TResult;
label?: string;
deps?: DepKey;
}): LiveQueryDef<TResult>;
<TResultSchema, TResult = TResultSchema>(queryInput: ((get: GetAtomResult) => QueryInputRaw<TResultSchema, ReadonlyArray<any>>) | ((get: GetAtomResult) => QueryBuilder<TResultSchema, any, any>), options?: {
map?: (rows: TResultSchema) => TResult;
label?: string;
deps?: DepKey;
}): LiveQueryDef<TResult>;
}

NOTE queryDb is only supposed to read data. Don't use it to insert/update/delete data but use events instead.

When using contextual data when constructing the query, please make sure to include it in the deps option.

@example

const todos$ = queryDb(tables.todos.where({ complete: true }))

@example

// Group-by raw SQL query
const colorCounts$ = queryDb({
query: sql`SELECT color, COUNT(*) as count FROM todos WHERE complete = ? GROUP BY color`,
schema: Schema.Array(Schema.Struct({
color: Schema.String,
count: Schema.Number,
})),
bindValues: [1],
})

@example

// Using contextual data when constructing the query
const makeFilteredQuery = (filter: string) =>
queryDb(tables.todos.where({ title: { op: 'like', value: filter } }), { deps: [filter] })
const filteredTodos$ = makeFilteredQuery('buy coffee')

queryDb
} from '@livestore/livestore'
import {
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 {
const tables: {
readonly 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: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, WithDefaults<...>, Schema<...>>;
readonly uiState: ClientDocumentTableDef<...>;
}
tables
} from './schema.ts'
const
const query$: LiveQueryDef<readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
}[], "def">
query$
=
queryDb<readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
}[], readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
}[]>(queryInput: QueryInputRaw<readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
}[], readonly any[]> | QueryBuilder<readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
}[], any, any>, options?: {
map?: (rows: readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
}[]) => readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
}[];
label?: string;
deps?: DepKey;
} | undefined): LiveQueryDef<...> (+1 overload)

NOTE queryDb is only supposed to read data. Don't use it to insert/update/delete data but use events instead.

When using contextual data when constructing the query, please make sure to include it in the deps option.

@example

const todos$ = queryDb(tables.todos.where({ complete: true }))

@example

// Group-by raw SQL query
const colorCounts$ = queryDb({
query: sql`SELECT color, COUNT(*) as count FROM todos WHERE complete = ? GROUP BY color`,
schema: Schema.Array(Schema.Struct({
color: Schema.String,
count: Schema.Number,
})),
bindValues: [1],
})

@example

// Using contextual data when constructing the query
const makeFilteredQuery = (filter: string) =>
queryDb(tables.todos.where({ title: { op: 'like', value: filter } }), { deps: [filter] })
const filteredTodos$ = makeFilteredQuery('buy coffee')

queryDb
(
const tables: {
readonly 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: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, WithDefaults<...>, Schema<...>>;
readonly 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: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, WithDefaults<...>, Schema<...>>
todos
.
where: (params: Partial<{
readonly id: string | {
op: QueryBuilder<TResult, TTableDef extends 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;
}>) => QueryBuilder<...> (+2 overloads)
where
({
completed?: boolean | {
op: QueryBuilder.WhereOps.SingleValue;
value: boolean;
} | {
op: QueryBuilder.WhereOps.MultiValue;
value: readonly boolean[];
} | undefined
completed
: true }).
orderBy: <"id">(col: "id", direction: "asc" | "desc") => QueryBuilder<readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
}[], 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: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema<boolean, number, never>;
default: Some<...>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, WithDefaults<...>>, "select" | ... 2 more ... | "row"> (+1 overload)
orderBy
('id', 'desc'), {
label?: string

Used for debugging / devtools

label
: 'completedTodos',
})
export const
const CompletedTodos: FC
CompletedTodos
:
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;
}[]
todos
=
const store: Store<LiveStoreSchema.Any, {}> & ReactApi
store
.
useQuery: <LiveQueryDef<readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
}[], "def">>(queryable: LiveQueryDef<readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
}[], "def">, options?: {
store?: Store;
}) => readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
}[]

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 query$: LiveQueryDef<readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
}[], "def">
query$
)
return (
<
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
{
const todos: readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
}[]
todos
.
ReadonlyArray<{ readonly id: string; readonly text: string; readonly completed: boolean; }>.map<JSX.Element>(callbackfn: (value: {
readonly id: string;
readonly text: string;
readonly completed: boolean;
}, index: number, array: readonly {
readonly id: string;
readonly text: string;
readonly completed: boolean;
}[]) => 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;
}
todo
) => (
<
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
React.Attributes.key?: React.Key | null | undefined
key
={
todo: {
readonly id: string;
readonly text: string;
readonly completed: boolean;
}
todo
.
id: string
id
}>{
todo: {
readonly id: string;
readonly text: string;
readonly completed: boolean;
}
todo
.
text: string
text
}</
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
))}
</
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
)
}
import {
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 {
const tables: {
readonly 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: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, WithDefaults<...>, Schema<...>>;
readonly uiState: ClientDocumentTableDef<...>;
}
tables
} from './schema.ts'
export const
const TodoItem: FC<{
id: string;
}>
TodoItem
:
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
<{
id: string
id
: string }> = ({
id: string
id
}) => {
const {
const store: Store<LiveStoreSchema.Any, {}> & ReactApi
store
} =
function useStore(options?: {
store?: Store;
}): {
store: Store & ReactApi;
}
useStore
()
const [
const todo: {
readonly text: string;
}
todo
,
const updateTodo: StateSetters<ClientDocumentTableDef<"UiState", {
readonly text: string;
}, {
readonly text: string;
}, {
partialSet: true;
default: {
id: undefined;
value: {
readonly text: "";
};
};
}>>
updateTodo
] =
const store: Store<LiveStoreSchema.Any, {}> & ReactApi
store
.
useClientDocument: <ClientDocumentTableDef<"UiState", {
readonly text: string;
}, {
readonly text: string;
}, {
partialSet: true;
default: {
id: undefined;
value: {
readonly text: "";
};
};
}>>(table: ClientDocumentTableDef<"UiState", {
readonly text: string;
}, {
readonly text: string;
}, {
partialSet: true;
default: {
id: undefined;
value: {
readonly text: "";
};
};
}>, id: string | typeof SessionIdSymbol, options?: Partial<RowQuery.GetOrCreateOptions<ClientDocumentTableDef<"UiState", {
readonly text: string;
}, {
readonly text: string;
}, {
partialSet: true;
default: {
id: undefined;
value: {
readonly text: "";
};
};
}>>> | undefined) => UseClientDocumentResult<...> (+1 overload)
useClientDocument
(
const tables: {
readonly 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: None<never>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
readonly completed: {
columnType: "integer";
schema: Schema<boolean, number, never>;
default: Some<false>;
nullable: false;
primaryKey: false;
autoIncrement: false;
};
}>, WithDefaults<...>, Schema<...>>;
readonly uiState: ClientDocumentTableDef<...>;
}
tables
.
uiState: ClientDocumentTableDef<"UiState", {
readonly text: string;
}, {
readonly text: string;
}, {
partialSet: true;
default: {
id: undefined;
value: {
readonly text: "";
};
};
}>
uiState
,
id: string
id
)
return (
<
React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
React.ButtonHTMLAttributes<HTMLButtonElement>.type?: "button" | "submit" | "reset" | undefined
type
="button"
React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined
onClick
={() =>
const updateTodo: (action: SetStateActionPartial<{
readonly text: string;
}>) => void
updateTodo
({
text?: string
text
: 'Hello, world!' })}>
{
const todo: {
readonly text: string;
}
todo
.
text: string
text
}
</
React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
>
)
}

LiveStore works with Vite out of the box.

LiveStore works with Tanstack Start out of the box.

LiveStore has a first-class integration with Expo / React Native via @livestore/adapter-expo.

Given various Next.js limitations, LiveStore doesn’t yet work with Next.js out of the box.

  • @livestore/react uses React.useState under the hood for useQuery / useClientDocument to bind LiveStore’s reactivity to React’s reactivity. Some libraries are using React.useExternalSyncStore for similar purposes but using React.useState in this case is more efficient and all that’s needed for LiveStore.
  • @livestore/react supports React Strict Mode.