Skip to content
IC Reactor

createActorHooks

createActorHooks is a factory function that creates a set of type-safe React hooks bound to a specific canister. It’s the primary way to integrate IC Reactor with React.

import { createActorHooks } from "@ic-reactor/react"
import { createActorHooks } from "@ic-reactor/react"
import { backend } from "./reactor"
const {
useActorQuery,
useActorSuspenseQuery,
useActorInfiniteQuery,
useActorSuspenseInfiniteQuery,
useActorMutation,
useActorMethod,
} = createActorHooks(backend)

Using a Reactor instance is the only supported way to create actor hooks:

import { Reactor, createActorHooks } from "@ic-reactor/react"
import { clientManager } from "./reactor"
import { idlFactory, type _SERVICE } from "../declarations/backend"
const backend = new Reactor<_SERVICE>({
clientManager,
idlFactory,
name: "backend",
canisterId: import.meta.env.VITE_BACKEND_CANISTER_ID,
})
const { useActorQuery, useActorMutation } = createActorHooks(backend)

With DisplayReactor (Auto Transformations)

Section titled “With DisplayReactor (Auto Transformations)”

To enable automatic display transformations (BigInt → string, Principal → text, etc.), use DisplayReactor:

import { DisplayReactor, createActorHooks } from "@ic-reactor/react"
import { clientManager } from "./reactor"
import { idlFactory, type _SERVICE } from "../declarations/backend"
const backend = new DisplayReactor<_SERVICE>({
clientManager,
idlFactory,
name: "backend",
canisterId: import.meta.env.VITE_BACKEND_CANISTER_ID,
})
// Hooks will use display types (string instead of bigint, etc.)
const { useActorQuery, useActorMutation } = createActorHooks(backend)
createActorHooks(reactor: Reactor<A, T>)
Parameter Type Description
reactor Reactor<A, T> A pre-created Reactor or DisplayReactor instance

createActorHooks returns an object containing:

Property Type Description
useActorQuery Hook Query hook for fetching data
useActorSuspenseQuery Hook Suspense-enabled query hook
useActorMutation Hook Mutation hook for updates
useActorMethod Hook Unified hook for queries & updates
useActorInfiniteQuery Hook Infinite query hook for pagination
useActorSuspenseInfiniteQuery Hook Suspense-enabled infinite query hook
src/reactor/index.ts
import { ClientManager, Reactor } from "@ic-reactor/react"
import { QueryClient } from "@tanstack/react-query"
import { idlFactory, type _SERVICE } from "../declarations/backend"
export const queryClient = new QueryClient()
export const clientManager = new ClientManager({
queryClient,
})
export const backend = new Reactor<_SERVICE>({
clientManager,
idlFactory,
canisterId: import.meta.env.VITE_BACKEND_CANISTER_ID,
name: "backend",
})
src/reactor/hooks.ts
import {
AuthenticationManager,
createActorHooks,
createAuthHooks,
} from "@ic-reactor/react"
import { backend, clientManager } from "./index"
// Create hooks for the backend canister
export const {
useActorQuery,
useActorMutation,
useActorSuspenseQuery,
useActorInfiniteQuery,
useActorSuspenseInfiniteQuery,
useActorMethod,
} = createActorHooks(backend)
// Create auth hooks
const authentication = new AuthenticationManager({ clientManager })
export const { useAuth, useUserPrincipal, useAgentState } =
createAuthHooks(authentication)

Add a reactor for the second canister next to backend, on the same ClientManager:

// src/reactor/index.ts, next to `backend`
import { Reactor } from "@ic-reactor/react"
import {
idlFactory as ledgerIdlFactory,
type _SERVICE as LedgerService,
} from "../declarations/ledger"
// `clientManager` is the one this file already builds above
export const ledger = new Reactor<LedgerService>({
clientManager,
idlFactory: ledgerIdlFactory,
canisterId: import.meta.env.VITE_LEDGER_CANISTER_ID,
name: "ledger",
})

Then bind hooks to each reactor in place of the hooks.ts above:

src/reactor/hooks.ts
import { createActorHooks } from "@ic-reactor/react"
import { backend, ledger } from "./index"
// Backend canister hooks
export const backendHooks = createActorHooks(backend)
// Ledger canister hooks
export const ledgerHooks = createActorHooks(ledger)
// Export individual hooks for convenience
export const {
useActorQuery: useBackendQuery,
useActorMutation: useBackendMutation,
} = backendHooks
export const {
useActorQuery: useLedgerQuery,
useActorMutation: useLedgerMutation,
} = ledgerHooks

You can define everything in one place:

src/reactor/hooks.ts
import {
AuthenticationManager,
ClientManager,
Reactor,
createActorHooks,
createAuthHooks,
} from "@ic-reactor/react"
import { QueryClient } from "@tanstack/react-query"
import { idlFactory, type _SERVICE } from "../declarations/backend"
const queryClient = new QueryClient()
const clientManager = new ClientManager({
queryClient,
})
const backend = new Reactor<_SERVICE>({
clientManager,
idlFactory,
name: "backend",
canisterId: import.meta.env.VITE_BACKEND_CANISTER_ID,
})
const authentication = new AuthenticationManager({ clientManager })
// Returns hooks
export const { useActorQuery, useActorMutation } = createActorHooks(backend)
export const { useAuth, useUserPrincipal } = createAuthHooks(authentication)
// Export for use elsewhere
export { queryClient, clientManager, backend }

createActorHooks preserves full type safety:

import { createActorHooks } from "@ic-reactor/react"
import { backend } from "./reactor"
const { useActorQuery, useActorMutation } = createActorHooks(backend)
function UserCard() {
// TypeScript knows all available methods
const { data } = useActorQuery({
functionName: "get_user", // ✅ Autocomplete shows valid methods
args: ["user-123"], // ✅ Type-checked arguments
})
const { mutate } = useActorMutation({
functionName: "create_user", // ✅ Autocomplete
})
return (
<button
onClick={() => mutate([{ name: "Alice", email: "[email protected]" }])} // ✅ Type-safe args
>
{data?.name}
</button>
)
}

The package exports types for all hooks with two naming conventions:

For hooks created by createActorHooks where the reactor is already bound:

import type {
UseActorQueryParameters,
UseActorQueryResult,
UseActorMutationParameters,
UseActorMutationResult,
UseActorSuspenseQueryParameters,
UseActorSuspenseQueryResult,
UseActorInfiniteQueryParameters,
UseActorInfiniteQueryResult,
UseActorSuspenseInfiniteQueryParameters,
UseActorSuspenseInfiniteQueryResult,
} from "@ic-reactor/react"

For direct hook usage where you pass the reactor explicitly:

import type {
UseReactorQueryParameters,
UseReactorQueryResult,
UseReactorMutationParameters,
UseReactorMutationResult,
UseReactorMethodParameters,
UseReactorMethodResult,
// ... and more
} from "@ic-reactor/react"