Data Client
Reactive Mutations
Render data with useSuspense(). Then mutate with Controller.fetch().
This updates all usages atomically and immediately with zero additional fetches. Reactive Data Client automatically ensures data consistency and integrity globally including even the most challenging race conditions.
import { UserResource } from './resources'; export default function ProfileEdit({ id }: { id: number }) { const user = useSuspense(UserResource.get, { id }); const controller = useController(); const handleChange = ({ currentTarget: { value: name } }) => controller.fetch(UserResource.partialUpdate, { id }, { name }); return ( <TextInput label="Name" value={user.name} onChange={handleChange} /> ); }
Structured data
Data consistency, performance, and typesafety scale even as your data becomes more complex.
Creates and deletes reactively update the correct lists, even when those lists are nested inside other objects.
Model even the most complex data with polymorphic and unbounded object/maps support.
import { TodoResource } from './resources'; export default function NewTodo({ userId }: { userId: number }) { const controller = useController(); const handleKeyDown = async e => { if (e.key === 'Enter') { controller.fetch(TodoResource.getList.push, { userId, title: e.currentTarget.value, }); e.currentTarget.value = ''; } }; return ( <div className="listItem nogap"> <label> <input type="checkbox" name="new" checked={false} disabled /> <TextInput size="small" onKeyDown={handleKeyDown} /> </label> <CancelButton /> </div> ); }
Live updates
Keep remote changes in sync with useLive().
Polling, SSE and Websocket or support a custom protocol with middlewares
import { getTicker } from './resources'; export default function AssetPrice({ symbol }: { symbol: string }) { const productId = `${symbol}-USD`; const ticker = useLive(getTicker, { productId }); return ( <tr> <th>{symbol}</th> <td align="right"> <NumberFlow value={ticker.price} format={{ style: 'currency', currency: 'USD' }} /> </td> </tr> ); }
Data Integrity
Strong inferred types; single source of truth that is referentially stable ensures consistency; asynchronous invariants make it easy to avoid race conditions
Performance
Normalized cache means data is often ready before it is even needed. Automatic request deduplication means less data to send over the network.
Composition over configuration
Declare what you need where you need it. Share data definitions across platforms, components, protocols, and behaviors.
Incremental Adoption
Get started fast with one line data definition and one line data binding. Then add TypeScript, normalized cache with Schemas, optimistic updates and more.