cantonjs-react
v0.4.0
Published
Participant-private React hooks for cantonjs applications
Maintainers
Readme
cantonjs-react
Participant-private React hooks for Canton ledger applications, powered by TanStack Query.
Use this package only once your app already has participant access. If that access comes from official wallet tooling, map the connected provider output into createLedgerClient(...) first and then pass that client into CantonProvider.
Install
npm install cantonjs cantonjs-react @tanstack/react-queryQuick Start
import { CantonProvider, useContracts, useCreateContract } from 'cantonjs-react'
import { createLedgerClient, jsonApi } from 'cantonjs'
const client = createLedgerClient({
transport: jsonApi({ url: 'http://localhost:7575', token: jwt }),
actAs: 'Alice::1234',
})
function App() {
return (
<CantonProvider client={client}>
<AssetList />
</CantonProvider>
)
}
function AssetList() {
const { data: assets, isLoading } = useContracts({
templateId: '#my-pkg:Main:Asset',
})
const { mutate: create, isPending } = useCreateContract({
templateId: '#my-pkg:Main:Asset',
})
if (isLoading) return <div>Loading...</div>
return (
<div>
<button
disabled={isPending}
onClick={() => create({ createArguments: { owner: 'Alice', value: 100 } })}
>
Create Asset
</button>
<ul>
{assets?.map(c => (
<li key={c.createdEvent.contractId}>
{JSON.stringify(c.createdEvent.createArgument)}
</li>
))}
</ul>
</div>
)
}Public Scan Data Alongside Ledger Hooks
cantonjs-react stays focused on participant-private ledger state. For public Splice data, use TanStack Query directly with cantonjs-splice-scan:
import { useQuery } from '@tanstack/react-query'
import { useContracts } from 'cantonjs-react'
import { createScanClient } from 'cantonjs-splice-scan'
const scan = createScanClient({
url: import.meta.env.VITE_SPLICE_SCAN_URL,
})
function NetworkDashboard() {
const { data: dso } = useQuery({
queryKey: ['scan', 'dso'],
queryFn: () => scan.getDsoInfo(),
})
const { data: assets } = useContracts({
templateId: '#my-pkg:Main:Asset',
})
return (
<div>
<pre>{JSON.stringify(dso, null, 2)}</pre>
<pre>{JSON.stringify(assets, null, 2)}</pre>
</div>
)
}This keeps public Scan reads and party-private ledger reads clearly separated. See ../../docs/examples/react.md for the full example.
Hooks
useContracts(options)
Query active contracts with automatic caching and deduplication.
const { data, isLoading, error } = useContracts({
templateId: '#my-pkg:Main:Asset',
enabled: true, // optional, default true
refetchInterval: 5000, // optional, auto-refetch in ms
})useCreateContract(options)
Mutation hook for creating contracts. Automatically invalidates related queries on success.
const { mutate: create, isPending, error } = useCreateContract({
templateId: '#my-pkg:Main:Asset',
onSuccess: (event) => console.log('Created:', event.contractId),
})
create({ createArguments: { owner: 'Alice', value: 100 } })useExercise(options)
Mutation hook for exercising choices. Automatically invalidates related queries on success.
const { mutate: exercise, isPending } = useExercise({
templateId: '#my-pkg:Main:Asset',
choice: 'Transfer',
})
exercise({
contractId: 'contract-id',
choiceArgument: { newOwner: 'Bob' },
})useStreamContracts(options)
Polling-based live contract updates (5-second interval).
const { contracts, isLoading, error } = useStreamContracts({
templateId: '#my-pkg:Main:Asset',
enabled: true, // optional
})useCantonClient()
Access the LedgerClient directly for advanced use cases.
const client = useCantonClient()useParty()
Get the current actAs party identity.
const party = useParty()
// 'Alice::1234'Provider
Wrap your app with CantonProvider. Optionally pass a custom QueryClient:
import { QueryClient } from '@tanstack/react-query'
const queryClient = new QueryClient({
defaultOptions: { queries: { staleTime: 10_000 } },
})
<CantonProvider client={ledgerClient} queryClient={queryClient}>
<App />
</CantonProvider>Cache Invalidation
Mutations automatically invalidate contract queries for the same template:
useCreateContractinvalidates['canton', 'contracts', templateId]useExerciseinvalidates['canton', 'contracts', templateId]
This means useContracts queries refresh automatically after mutations complete.
Peer Dependencies
| Package | Version |
|---------|---------|
| react | ^18.0.0 || ^19.0.0 |
| @tanstack/react-query | ^5.0.0 |
Requirements
- Node.js >= 18
- React 18 or 19
Related
- cantonjs — Core TypeScript library for Canton
- cantonjs-codegen — DAR-to-TypeScript code generation
