DisplayReactor
Defined in: core/src/display-reactor.ts:150
DisplayReactor provides automatic type transformations between Candid and display-friendly types, plus optional argument validation.
Type Transformations
Section titled “Type Transformations”bigint→string(for JSON/UI display)Principal→string(text representation)[T] | []→T | undefined(optional unwrapping;nullis also accepted as none in arguments)- Blobs (
vec nat8) → hex strings, at every size
Validation (Optional)
Section titled “Validation (Optional)”Register validators to check arguments before canister calls. Validators receive display types (strings), making them perfect for form validation.
Use DisplayReactor for UI/forms where principals and numeric values should
be string-friendly. Use Reactor when you need raw Candid types directly.
Example
Section titled “Example”import { DisplayReactor } from "@ic-reactor/core"
const reactor = new DisplayReactor<_SERVICE>({ clientManager, name: "backend", canisterId: "...", idlFactory,})
// Optional: Add validationreactor.registerValidator("transfer", ([input]) => { if (!input.to) { return { success: false, issues: [{ path: ["to"], message: "Recipient is required" }] } } return { success: true }})
// Call with display typesawait reactor.callMethod({ functionName: "transfer", args: [{ to: "aaaaa-aa", amount: "100" }], // strings!})Extends
Section titled “Extends”Reactor<A,T>
Type Parameters
Section titled “Type Parameters”A = BaseActor
The actor service type, in Candid types. The display types
are derived from it. Without it (BaseActor), every method’s display-side
arguments and results are typed unknown, where a raw Reactor gives
any: pass the service type, or cast to the display shape you expect.
T extends TransformKey = "display"
Constructors
Section titled “Constructors”Constructor
Section titled “Constructor”new DisplayReactor<
A,T>(config):DisplayReactor<A,T>
Defined in: core/src/display-reactor.ts:161
Parameters
Section titled “Parameters”config
Section titled “config”Returns
Section titled “Returns”DisplayReactor<A, T>
Overrides
Section titled “Overrides”Properties
Section titled “Properties”transform
Section titled “transform”
readonlytransform:T
Defined in: core/src/display-reactor.ts:154
Overrides
Section titled “Overrides”_actor
Section titled “_actor”
readonly_actor:A
Defined in: core/src/reactor.ts:162
Phantom type brand for inference - never assigned at runtime
Inherited from
Section titled “Inherited from”clientManager
Section titled “clientManager”clientManager:
ClientManager
Defined in: core/src/reactor.ts:164
Inherited from
Section titled “Inherited from”name:
string
Defined in: core/src/reactor.ts:165
Inherited from
Section titled “Inherited from”canisterId
Section titled “canisterId”canisterId:
Principal
Defined in: core/src/reactor.ts:166
Inherited from
Section titled “Inherited from”service
Section titled “service”service:
ServiceClass
Defined in: core/src/reactor.ts:167
Inherited from
Section titled “Inherited from”pollingOptions
Section titled “pollingOptions”pollingOptions:
PollingOptions
Defined in: core/src/reactor.ts:168
Inherited from
Section titled “Inherited from”Accessors
Section titled “Accessors”queryClient
Section titled “queryClient”Get Signature
Section titled “Get Signature”get queryClient():
QueryClient
Defined in: core/src/reactor.ts:993
Get the query client from clientManager. This is the recommended way to access the query client for direct queries.
Returns
Section titled “Returns”QueryClient
Inherited from
Section titled “Inherited from”Get Signature
Section titled “Get Signature”get agent():
HttpAgent
Defined in: core/src/reactor.ts:1001
Get the agent from clientManager. This is the recommended way to access the agent for direct calls.
Returns
Section titled “Returns”HttpAgent
Inherited from
Section titled “Inherited from”Methods
Section titled “Methods”getCodec()
Section titled “getCodec()”getCodec<
M>(methodName):ActorMethodCodecs<A,M> |null
Defined in: core/src/display-reactor.ts:225
Get a codec for a specific method. Returns the args and result codecs for bidirectional transformation.
Type Parameters
Section titled “Type Parameters”M extends string
Parameters
Section titled “Parameters”methodName
Section titled “methodName”M
The name of the method
Returns
Section titled “Returns”ActorMethodCodecs<A, M> | null
Object with args and result codecs, or null if not found
registerValidator()
Section titled “registerValidator()”registerValidator<
M>(methodName,validator):void
Defined in: core/src/display-reactor.ts:261
Register a validator for a specific method. Validators receive display types (strings for Principal/bigint).
Type Parameters
Section titled “Type Parameters”M extends string
Parameters
Section titled “Parameters”methodName
Section titled “methodName”M
The name of the method to validate
validator
Section titled “validator”DisplayValidator<A, M>
The validator function receiving display types
Returns
Section titled “Returns”void
Example
Section titled “Example”// input.to is string, input.amount is stringreactor.registerValidator("transfer", ([input]) => { if (!/^\d+$/.test(input.amount)) { return { success: false, issues: [{ path: ["amount"], message: "Must be a valid number" }] } } return { success: true }})unregisterValidator()
Section titled “unregisterValidator()”unregisterValidator<
M>(methodName):void
Defined in: core/src/display-reactor.ts:271
Unregister a validator for a specific method.
Type Parameters
Section titled “Type Parameters”M extends string
Parameters
Section titled “Parameters”methodName
Section titled “methodName”M
Returns
Section titled “Returns”void
hasValidator()
Section titled “hasValidator()”hasValidator<
M>(methodName):boolean
Defined in: core/src/display-reactor.ts:278
Check if a method has a registered validator.
Type Parameters
Section titled “Type Parameters”M extends string
Parameters
Section titled “Parameters”methodName
Section titled “methodName”M
Returns
Section titled “Returns”boolean
validate()
Section titled “validate()”validate<
M>(methodName,args):Promise<ValidationResult>
Defined in: core/src/display-reactor.ts:312
Validate arguments without calling the canister. Arguments are in display format (strings for Principal/bigint). Useful for form validation before submission.
Async validators run here, including fromZodSchema(schema, { async: true }).
A validator that throws or rejects makes this reject with a CallError
whose cause is what it threw, as callMethod() and
callMethodWithValidation() do; a ValidationError it throws is passed
on as it is.
Type Parameters
Section titled “Type Parameters”M extends string
Parameters
Section titled “Parameters”methodName
Section titled “methodName”M
The name of the method
ReactorArgs<A, M, T>
The display-type arguments to validate
Returns
Section titled “Returns”Promise<ValidationResult>
ValidationResult indicating success or failure
Example
Section titled “Example”// Validate form data before submissionconst result = await reactor.validate("transfer", [{ to: formData.recipient, // string amount: formData.amount, // string}])
if (!result.success) { result.issues.forEach(issue => { form.setError(issue.path[0], issue.message) })}callMethodWithValidation()
Section titled “callMethodWithValidation()”callMethodWithValidation<
M>(params):Promise<ReactorReturnOk<A,M,T>>
Defined in: core/src/display-reactor.ts:376
Call a method with async validation support.
Use this instead of callMethod() when you have async validators, such as
fromZodSchema(schema, { async: true }).
A failed validation rejects with a ValidationError, and a validator
that throws or rejects with a CallError whose cause is what it threw.
Type Parameters
Section titled “Type Parameters”M extends string
Parameters
Section titled “Parameters”params
Section titled “params”functionName
Section titled “functionName”M
ReactorArgs<A, M, T>
callConfig?
Section titled “callConfig?”CallConfig
Returns
Section titled “Returns”Promise<ReactorReturnOk<A, M, T>>
Example
Section titled “Example”// Async validator (e.g., check if address is blocked)reactor.registerValidator("transfer", async ([input]) => { const isBlocked = await checkBlocklist(input.to) if (isBlocked) { return { success: false, issues: [{ path: ["to"], message: "Address is blocked" }] } } return { success: true }})
await reactor.callMethodWithValidation({ functionName: "transfer", args: [{ to: "...", amount: "100" }],})setCanisterId()
Section titled “setCanisterId()”setCanisterId(
canisterId):void
Defined in: core/src/reactor.ts:255
Set the canister ID for this reactor. Useful for dynamically switching between canisters of the same type (e.g., multiple ICRC tokens).
Parameters
Section titled “Parameters”canisterId
Section titled “canisterId”The new canister ID (as string or Principal)
Returns
Section titled “Returns”void
Example
Section titled “Example”// Switch to a different ledger canisterledgerReactor.setCanisterId("ryjl3-tyaaa-aaaaa-aaaba-cai")
// Then use queries/mutations as normalconst { data } = icrc1NameQuery.useQuery()Inherited from
Section titled “Inherited from”setCanisterName()
Section titled “setCanisterName()”setCanisterName(
name):void
Defined in: core/src/reactor.ts:276
Set the canister name for this reactor. Useful for dynamically switching between canisters of the same type (e.g., multiple ICRC tokens).
Parameters
Section titled “Parameters”string
The new canister name
Returns
Section titled “Returns”void
Example
Section titled “Example”// Switch to a different ledger canisterledgerReactor.setCanisterName("icrc1")
// Then use queries/mutations as normalconst { data } = icrc1NameQuery.useQuery()Inherited from
Section titled “Inherited from”forCanister()
Section titled “forCanister()”forCanister(
canisterId):this
Defined in: core/src/reactor.ts:329
A reactor of the same class for another canister of the same interface,
such as another ICRC ledger. It shares this reactor’s ClientManager
(so its agent, identity and QueryClient), name and polling options. It
starts from the interface, transform and validators this reactor has
when it is made. Only the canister differs.
The same canister id always gives the same reactor, so it is safe to
call during render and as a dependency of useMemo. The siblings of a
reactor share that memo: a.forCanister(x).forCanister(y) is
a.forCanister(y). The result is a separate reactor even for this
reactor’s own canister, and it keeps its canister when this one’s
setCanisterId moves.
Use one sibling per canister instead of retargeting a shared reactor
with setCanisterId. Their query keys start with their own
canister, so several tokens’ queries live side by side in the cache,
and no call or retry of one is sent to another. A mutation invalidates
its own canister’s queries. Never setCanisterId a sibling: ask for the
other canister’s instead.
A subclass whose constructor takes options of its own passes them on by
overriding the protected siblingParameters(canisterId). Its constructor
has to build the reactor for the canisterId it is given: one that sets
a canister of its own makes this throw rather than hand out a reactor
for the wrong canister.
Parameters
Section titled “Parameters”canisterId
Section titled “canisterId”The other canister, as text or a Principal.
Returns
Section titled “Returns”this
Example
Section titled “Example”const ledger = new DisplayReactor<Ledger>({ clientManager, idlFactory, name: "ledger", canisterId: "ryjl3-tyaaa-aaaaa-aaaba-cai", // ICP})
// ckBTC, through the same agent, cache and interfaceconst ckbtc = ledger.forCanister("mxzaz-hqaaa-aaaar-qaada-cai")const symbol = await ckbtc.fetchQuery({ functionName: "icrc1_symbol" })
// In React: one set of hooks per token, memoized by its canisterconst hooks = useMemo( () => createActorHooks(ledger.forCanister(tokenId)), [tokenId])Inherited from
Section titled “Inherited from”getServiceInterface()
Section titled “getServiceInterface()”getServiceInterface():
ServiceClass
Defined in: core/src/reactor.ts:397
Get the service interface (IDL.ServiceClass) for this reactor. Useful for introspection and codec generation.
Returns
Section titled “Returns”ServiceClass
The service interface
Inherited from
Section titled “Inherited from”isQueryMethod()
Section titled “isQueryMethod()”isQueryMethod<
M>(methodName):boolean
Defined in: core/src/reactor.ts:423
Check if a method is a query method (query or composite_query).
Type Parameters
Section titled “Type Parameters”M extends string
Parameters
Section titled “Parameters”methodName
Section titled “methodName”M
Returns
Section titled “Returns”boolean
Inherited from
Section titled “Inherited from”generateQueryKey()
Section titled “generateQueryKey()”generateQueryKey<
M>(params,callConfig?): readonlyunknown[]
Defined in: core/src/reactor.ts:465
Type Parameters
Section titled “Type Parameters”M extends string
Parameters
Section titled “Parameters”params
Section titled “params”ReactorQueryParams<A, M, T>
callConfig?
Section titled “callConfig?”CallConfig
Returns
Section titled “Returns”readonly unknown[]
Inherited from
Section titled “Inherited from”getQueryRetry()
Section titled “getQueryRetry()”getQueryRetry<
M>(functionName,queryKey): ((failureCount,error) =>boolean) |undefined
Defined in: core/src/reactor.ts:590
The retry a TanStack query of functionName, cached under queryKey,
runs with when the query sets no retry of its own.
For a query method it is undefined, and the QueryClient’s retry
defaults apply as usual.
An update method runs on the canister again each time the query function
runs, as a new call the IC cannot tell from a retry, so a retry after a
lost response executed the update a second time. For one it is a function
that retries only a failure proving the canister never ran the call, a
SysTransient rejection (see isRetryableUpdateError), and only as often
as the QueryClient’s retry default for queryKey would: its
setQueryDefaults or defaultOptions.queries, or TanStack Query’s own
three retries in a browser when neither sets one. With the QueryClient
defineReactor creates, that is reactorUpdateRetry, and with a default
of retry: false nothing is retried. A transport failure, a SysUnknown
rejection and an HTTP error are not retried. Refetches on mount, window
focus, reconnect and invalidation still run the method again.
getQueryOptions, fetchQuery and the query hooks and
factories of @ic-reactor/react apply it, and a retry the query sets
itself wins over it.
Type Parameters
Section titled “Type Parameters”M extends string
Parameters
Section titled “Parameters”functionName
Section titled “functionName”M
The method the query calls.
queryKey
Section titled “queryKey”readonly unknown[]
The query’s key, which selects its QueryClient defaults.
Returns
Section titled “Returns”((failureCount, error) => boolean) | undefined
Inherited from
Section titled “Inherited from”getQueryOptions()
Section titled “getQueryOptions()”getQueryOptions<
M>(params):FetchQueryOptions<ReactorQueryData<ReactorReturnOk<A,M,T>>>
Defined in: core/src/reactor.ts:613
The key and function of a TanStack query of the method, for
queryClient.fetchQuery, prefetchQuery or useQuery. For an update
method they also hold the retry from getQueryRetry; spread a
retry of your own after them to replace it.
Type Parameters
Section titled “Type Parameters”M extends string
Parameters
Section titled “Parameters”params
Section titled “params”ReactorCallParams<A, M, T>
Returns
Section titled “Returns”FetchQueryOptions<ReactorQueryData<ReactorReturnOk<A, M, T>>>
Inherited from
Section titled “Inherited from”invalidateQueries()
Section titled “invalidateQueries()”invalidateQueries<
M>(params?,callConfig?):Promise<void>
Defined in: core/src/reactor.ts:677
Invalidate cached queries for this canister. This will mark matching queries as stale and trigger a refetch for any active queries.
It returns TanStack Query’s promise, which resolves once the active
queries it matched have refetched. A refetch that fails does not reject
it. Await it where the next step should read the refetched data, such as
in a mutation’s onSuccess; an arrow that returns it, like
onSuccess: () => reactor.invalidateQueries(...), keeps the mutation
pending until those refetches finish.
Type Parameters
Section titled “Type Parameters”M extends string
Parameters
Section titled “Parameters”params?
Section titled “params?”Partial<ReactorQueryParams<A, M, T>>
Optional parameters to filter the invalidation. Without a
functionName, every query of the canister is invalidated.
callConfig?
Section titled “callConfig?”CallConfig
Optional call configuration. Its canisterId selects
which canister’s queries are invalidated, as it does for the calls.
Returns
Section titled “Returns”Promise<void>
Example
Section titled “Example”// Invalidate all queries for this canister, and wait for the active// ones to refetchawait reactor.invalidateQueries()
// Invalidate only 'getUser' queriesreactor.invalidateQueries({ functionName: 'getUser' })
// Invalidate 'getUser' query for specific userreactor.invalidateQueries({ functionName: 'getUser', args: ['user-1'] })
// Invalidate all queries of a canister reached through an overridereactor.invalidateQueries(undefined, { canisterId: otherLedgerId })Inherited from
Section titled “Inherited from”callMethod()
Section titled “callMethod()”callMethod<
M>(params):Promise<ReactorReturnOk<A,M,T>>
Defined in: core/src/reactor.ts:730
Call a canister method directly using agent.call() or agent.query(). This is the recommended approach for interacting with canisters.
Type Parameters
Section titled “Type Parameters”M extends string
Parameters
Section titled “Parameters”params
Section titled “params”Omit<ReactorCallParams<A, M, T>, "queryKey">
Returns
Section titled “Returns”Promise<ReactorReturnOk<A, M, T>>
Example
Section titled “Example”// Query methodconst result = await reactor.callMethod({ functionName: 'greet', args: ['world'],});
// Update method with optionsconst result = await reactor.callMethod({ functionName: 'transfer', args: [{ to: principal, amount: 100n }], callConfig: { effectiveCanisterId: principal },});Inherited from
Section titled “Inherited from”fetchQuery()
Section titled “fetchQuery()”fetchQuery<
M>(params,options?):Promise<ReactorQueryData<ReactorReturnOk<A,M,T>>>
Defined in: core/src/reactor.ts:832
Returns the cached value for the call, or fetches and caches it when there
is none. Like TanStack Query’s ensureQueryData, it is cache-first: a
cached value is returned even when it is stale or was invalidated, and a
staleTime in options has no effect. For a value the canister returns
now, use callMethod, or queryClient.fetchQuery with the options
from getQueryOptions inside
ClientManager.fetchAcrossIdentitySwitch, which keeps a sign-in or
sign-out from resolving it with the previous principal’s cached data.
A sign-in or sign-out while the fetch is in flight cancels it, so the
previous identity’s answer is never cached. The fetch then runs again for
the identity installed now and resolves with that answer, rather than
rejecting with TanStack’s CancelledError; see
ClientManager.fetchAcrossIdentitySwitch.
Type Parameters
Section titled “Type Parameters”M extends string
Parameters
Section titled “Parameters”params
Section titled “params”ReactorCallParams<A, M, T>
options?
Section titled “options?”Omit<FetchQueryOptions<ReactorQueryData<ReactorReturnOk<A, M, T>>, ReactorReturnErr<A, M, T>, ReactorQueryData<ReactorReturnOk<A, M, T>>, readonly unknown[], never>, "queryKey" | "queryFn">
Further TanStack Query options for the fetch, such as
retry, networkMode or meta. The query key and function always come
from params. The query factories pass their config’s options through
here, so a subclass that overrides this method still sees their fetches.
Without a retry here, an update method retries as
getQueryRetry says.
Returns
Section titled “Returns”Promise<ReactorQueryData<ReactorReturnOk<A, M, T>>>
Inherited from
Section titled “Inherited from”getQueryData()
Section titled “getQueryData()”getQueryData<
M>(params,callConfig?):ReactorQueryData<ReactorReturnOk<A,M,T>> |undefined
Defined in: core/src/reactor.ts:870
Get the current data from the cache without fetching.
Type Parameters
Section titled “Type Parameters”M extends string
Parameters
Section titled “Parameters”params
Section titled “params”ReactorQueryParams<A, M, T>
callConfig?
Section titled “callConfig?”CallConfig
Returns
Section titled “Returns”ReactorQueryData<ReactorReturnOk<A, M, T>> | undefined
Inherited from
Section titled “Inherited from”subnetId()
Section titled “subnetId()”subnetId():
Promise<Principal>
Defined in: core/src/reactor.ts:973
Get the subnet ID for this canister.
Returns
Section titled “Returns”Promise<Principal>
Inherited from
Section titled “Inherited from”subnetState()
Section titled “subnetState()”subnetState(
options):Promise<ReadStateResponse>
Defined in: core/src/reactor.ts:980
Get the subnet state for this canister.
Parameters
Section titled “Parameters”options
Section titled “options”ReadStateOptions
Returns
Section titled “Returns”Promise<ReadStateResponse>