Skip to Content
React Live Queries

React Live Queries

@kalamdb/react gives React apps hook-first live-query APIs on top of the shared KalamDB TypeScript client. Use it for typed Drizzle screens, raw SQL live views, multi-query dashboards, and AI assistant workspaces with typing, tool calls, and human approvals.

Install @kalamdb/react

bash snippetBASH
npm i @kalamdb/client @kalamdb/react react react-domnpm i @kalamdb/orm drizzle-orm

Wrap your app with a single KalamDBClient:

tsx snippetTSX
import { Auth, createClient } from '@kalamdb/client';import { KalamProvider } from '@kalamdb/react'; const client = createClient({  url: 'http://localhost:8080',  authProvider: async () => Auth.basic('admin', 'AdminPass123!'),}); export function App() {  return (    <KalamProvider client={client}>      <ChatScreen />    </KalamProvider>  );}

Typed Drizzle Mode

Use generated tables from @kalamdb/orm when you want typed rows and typed mutations.

tsx snippetTSX
import { LiveQuery } from '@kalamdb/react';import { asc, eq } from 'drizzle-orm';import { messages } from './schema.generated'; export function MessagesPane({ conversationId }: { conversationId: string }) {  return (    <LiveQuery      table={messages}      where={(table) => eq(table.conversationId, conversationId)}      orderBy={(table) => asc(table.createdAt)}      deps={[conversationId]}    >      {({ rows, state, insert }) => (        <section>          {rows.map((row) => <article key={row.id}>{row.body}</article>)}          <button            disabled={state.inserting}            onClick={() => insert(messages).values({              id: crypto.randomUUID(),              conversationId,              role: 'user',              body: 'Hello',              status: 'sent',              createdAt: new Date(),              updatedAt: new Date(),            })}          >            Send          </button>        </section>      )}    </LiveQuery>  );}

Raw SQL Mode

Raw SQL mode is useful for quick admin views and non-Drizzle code. It supports KalamDB’s live-compatible subset and normalizes safe ORDER BY and LIMIT clauses into client-side projection.

tsx snippetTSX
import { LiveQuery } from '@kalamdb/react'; export function SqlMessagesPane() {  return (    <LiveQuery query="SELECT * FROM chat.messages WHERE room = 'main' ORDER BY created_at ASC" getKey="id">      {({ rows, state }) => (        <section>{state.loading ? 'Loading' : rows.length}</section>      )}    </LiveQuery>  );}

Multi-Query Assistant Screens

useLiveQueries opens one live controller per named dataset. useLiveSelection derives screen-ready state without copying live rows into effect-managed local state.

tsx snippetTSX
import { useLiveQueries, useLiveSelection } from '@kalamdb/react';import { asc, eq } from 'drizzle-orm';import { approvals, messages, toolCalls, typing } from './schema.generated'; export function AssistantWorkspace({ conversationId }: { conversationId: string }) {  const live = useLiveQueries({    queries: {      messages: {        table: messages,        where: (table) => eq(table.conversationId, conversationId),        orderBy: (table) => asc(table.createdAt),        deps: [conversationId],      },      typing: { table: typing, where: (table) => eq(table.conversationId, conversationId), deps: [conversationId] },      toolCalls: { table: toolCalls, where: (table) => eq(table.conversationId, conversationId), deps: [conversationId] },      approvals: { table: approvals, where: (table) => eq(table.conversationId, conversationId), deps: [conversationId] },    },    deps: [conversationId],  });   const assistant = useLiveSelection(live, (context) => ({    messages: context.messages.rows,    typingUsers: context.typing.rows.map((row) => row.userName),    activeTools: context.toolCalls.rows.filter((row) => row.status !== 'completed'),    pendingApprovals: context.approvals.rows.filter((row) => row.status === 'pending'),    approve: (approvalId: string) => context.update(approvals, approvalId).set({ status: 'approved' }),  }));   return <AssistantLayout {...assistant} busy={live.state.loading || live.state.updating} />;}

Rows stay authoritative from KalamDB live streams. Mutation state is local UI state for disabling buttons, showing progress, and surfacing errors.

React AI Chat Example

The KalamDB repo includes examples/react-ai-chat, a runnable validation app for the React package. It demonstrates a conversation sidebar, conversation history loading, multi-file sends, typing state, streamed assistant activity, message edit/cancel actions, tool-call timelines, and human approvals.

bash snippetBASH
cd examples/react-ai-chatnpm installnpm run setupnpm run dev

The app defaults to demo mode so you can try the React components without a server. Apply chat-app.sql, set VITE_KALAMDB_DEMO_MODE=false, and run npm run agent when you want the server-backed topic-agent path.

Last updated on