SDK
React Hooks
React bindings for Decentrl using useSyncExternalStore for tear-free reads of encrypted state.
@decentrl/sdk-react provides React hooks that connect your components to the Decentrl client. Built on useSyncExternalStore for tear-free concurrent reads.
Installation
npm install @decentrl/sdk-reactProvider Setup
Wrap your app with DecentrlProvider:
import { DecentrlProvider } from '@decentrl/sdk-react'
function App() {
return (
<DecentrlProvider client={client}>
<Chat />
</DecentrlProvider>
)
}Core Hooks
useDecentrl()
Returns the publish method and the client instance:
import { useDecentrl } from '@decentrl/sdk-react'
function SendButton() {
const { publish, client } = useDecentrl()
const send = () => publish('message', {
text: 'Hello',
threadId: crypto.randomUUID(),
})
return <button onClick={send}>Send</button>
}useDecentrlState(selector?)
Subscribes to client state with an optional selector function:
import { useDecentrlState } from '@decentrl/sdk-react'
// Full state
const state = useDecentrlState()
// With selector — only re-renders when messages change
const messages = useDecentrlState(s => s.messages)
const count = useDecentrlState(s => s.messages.length)useDecentrlIdentity()
Manages identity state and operations:
import { useDecentrlIdentity } from '@decentrl/sdk-react'
function IdentitySetup() {
const { identity, isInitialized, create, contracts } = useDecentrlIdentity()
if (!isInitialized) {
return (
<button onClick={() => create({
alias: 'alice',
mediatorDid: 'did:web:mediator.decentrl.io',
})}>
Create Identity
</button>
)
}
return <p>DID: {identity.did}</p>
}useAutoSync(options?)
Starts automatic background sync. Cleans up on unmount:
import { useAutoSync } from '@decentrl/sdk-react'
function App() {
useAutoSync({
intervalMs: 3000,
websocket: true,
onError: (err) => console.error(err),
})
return <Chat />
}useConnectionStatus()
const status = useConnectionStatus()
// 'disconnected' | 'connecting' | 'authenticating' | 'connected'Contract Hooks
import {
useActiveContracts,
usePendingContracts,
useContractByDid,
useRequestContract,
useAcceptContract,
} from '@decentrl/sdk-react'
// List active contracts
const { contracts, refresh, isRefreshing } = useActiveContracts()
// List pending inbound requests
const { data: pending, refetch } = usePendingContracts()
// Find contract by DID
const contract = useContractByDid(bobDid)
// Request a contract (mutation hook)
const { mutate: requestContract, isPending } = useRequestContract()
requestContract({ recipientDid: bobDid })
// Accept a contract (mutation hook)
const { mutate: acceptContract } = useAcceptContract()
acceptContract({
pendingId: request.id,
encryptedPayload: request.encryptedPayload,
requestorEphemeralPublicKey: request.requestorEphemeralPublicKey,
})Public Event Hooks
usePublishPublic()
Mutation hook for publishing public events:
import { usePublishPublic } from '@decentrl/sdk-react'
function PublishButton() {
const { mutate: publishPublic, isPending } = usePublishPublic()
return (
<button
disabled={isPending}
onClick={() => publishPublic(['blog.post', { title: 'Hello', body: 'World' }])}
>
Publish
</button>
)
}usePublicEventQuery(options)
Query public events from any publisher with pagination:
import { usePublicEventQuery } from '@decentrl/sdk-react'
function PublicFeed({ publisherDid }: { publisherDid: string }) {
const { data, isLoading, hasMore, fetchMore, refetch } = usePublicEventQuery({
publisherDid,
channelId: 'blog',
tags: ['featured'],
pageSize: 10,
})
if (isLoading) return <p>Loading...</p>
return (
<div>
{data.map((event) => (
<article key={event.id}>
<p>{JSON.parse(event.event).data.title}</p>
<small>{new Date(event.timestamp * 1000).toLocaleString()}</small>
</article>
))}
{hasMore && <button onClick={fetchMore}>Load more</button>}
</div>
)
}| Option | Type | Required | Description |
|---|---|---|---|
publisherDid | string | Yes | DID of the publisher to query |
channelId | string | No | Filter by channel |
tags | string[] | No | Filter by tags (OR semantics) |
pageSize | number | No | Results per page (default 20) |
enabled | boolean | No | Disable the query (default true) |
Event Hooks
useEventStream(callback, options?)
Subscribe to real-time events with optional filtering:
import { useEventStream } from '@decentrl/sdk-react'
useEventStream(
(event) => console.log('New:', event.type, event.data),
{ types: ['message'] },
)useEventQuery(options)
Query historical events with pagination and state selection:
import { useEventQuery } from '@decentrl/sdk-react'
const { data: messages, isLoading, hasMore, fetchMore } = useEventQuery({
tags: ['thread.abc'],
select: (state) => state.messages,
pageSize: 20,
})