/** * Example UI component showing the read + write patterns customers should * use throughout the rest of the app: * * - Reads use `useQuery`. The result is reactive — when any row matched * by the query changes (locally or via a sync push from another client), * the component re-renders automatically. There's no `useEffect`, no * manual subscription, no fetch on mount. * - Writes go straight to the local DB via `db.execute`. The call resolves * as soon as the row is in local SQLite (milliseconds), and the upload * to the server happens asynchronously in the background. The UI never * waits on the network. * * IDs are generated client-side with `uuid()`. This is intentional: it lets * the row exist locally before the server has heard about it, which is what * makes offline-first work. The server upserts on the id we send. */ import { useQuery } from '@powersync/react'; import { useState } from 'react'; import { v4 as uuid } from 'uuid'; import { db } from './lib/sync'; export default function App() { // The SQL is plain SQLite. Joins, aggregates, ORDER BY — anything SQLite // understands is fair game. Parameters can be passed as a second argument: // `useQuery('SELECT * FROM items WHERE done = ?', [0])`. const { data: items } = useQuery<{ id: string; text: string; done: number }>( 'SELECT * FROM items ORDER BY created_at DESC', ); const [draft, setDraft] = useState(''); const addItem = async (event: React.FormEvent) => { event.preventDefault(); const text = draft.trim(); if (!text) return; // INSERT writes to local SQLite. The connector's upload loop picks it // up on the next tick and POSTs it to /sync. await db.execute( 'INSERT INTO items (id, text, done, created_at) VALUES (?, ?, ?, ?)', [uuid(), text, 0, Date.now()], ); setDraft(''); }; const toggle = async (id: string, done: number) => { await db.execute('UPDATE items SET done = ? WHERE id = ?', [done ? 0 : 1, id]); }; return (