Skip to content
IC Reactor

@ic-reactor/react

@ic-reactor/react is the recommended package for React applications. It re-exports the runtime classes from @ic-reactor/core and adds hook factories, auth hooks, direct reactor hooks, and reusable query factories designed around TanStack Query.

  • You want idiomatic React hooks for queries, mutations, suspense, and auth.
  • You want ClientManager, Reactor, and DisplayReactor from one package, in client components and in React Server Components alike (a server component resolves the package’s hook-free react-server entry; see Server-Side Rendering).
  • You want to keep your app code focused on components instead of manual query wiring.
Terminal window
pnpm add @ic-reactor/react @tanstack/react-query @icp-sdk/core
# Optional: Internet Identity support (@icp-sdk/auth v8)
pnpm add @icp-sdk/auth

react is the only required React peer — react-dom is declared as an optional peer and never imported. @icp-sdk/auth is optional too: it is loaded through a literal import("@icp-sdk/auth/client") inside a try block, which webpack-family bundlers treat as declaring an optional dependency — with the peer absent the build succeeds and prints one Module not found: Can't resolve '@icp-sdk/auth/client' warning. Install the peer to remove the warning, or silence it with ignoreWarnings (in Next.js, assign it inside the webpack(config) callback):

webpack.config.js
ignoreWarnings: [{ module: /@ic-reactor\/react/, message: /@icp-sdk\/auth/ }]

That optional-try treatment is webpack-specific — other bundlers may fail to resolve the missing specifier at build time. If yours does, install the peer, or construct the AuthClient yourself and pass it as authClient to AuthenticationManager, in which case IC Reactor never imports @icp-sdk/auth at all.

The package requires Node.js 18+ (declared in engines).

import { ClientManager, Reactor, createActorHooks } from "@ic-reactor/react"
import { QueryClient } from "@tanstack/react-query"
import { canisterId, idlFactory, type _SERVICE } from "./declarations/backend"
const queryClient = new QueryClient()
export const clientManager = new ClientManager({ queryClient })
export const backend = new Reactor<_SERVICE>({
clientManager,
idlFactory,
name: "backend",
// Required unless the Vite plugin injects an `ic_env` cookie for this
// canister on a local replica. Without it the reactor constructor throws
// on a server and on any deployed origin.
canisterId,
})
export const { useActorQuery, useActorMutation } = createActorHooks(backend)

What each setup path adds to a browser bundle, measured with esbuild 0.28 (minified ESM, @ic-reactor/core bundled). The peers react, @tanstack/react-query and @icp-sdk/* are left out, since an app ships them either way; so is @icp-sdk/auth, which loads as its own chunk on first use.

Setup Minified Gzipped zod
createActorHooks + Reactor + ClientManager 31 kB 9.8 kB no
… + AuthenticationManager + createAuthHooks 52 kB 14.9 kB no
… + IdentityAttributesManager + createIdentityAttributeHooks 58 kB 16.7 kB no
createActorHooks + DisplayReactor + ClientManager 129 kB 37.3 kB yes
defineDisplayReactor 158 kB 45.4 kB yes
defineReactor 158 kB 45.4 kB yes

DisplayReactor builds its codecs on zod’s classic API, which does not tree-shake. That is about 85 kB minified (24 kB gzipped) of every row marked “yes”; an app that already bundles zod for its own code pays it once.

defineReactor costs as much as defineDisplayReactor today, even without display: its deprecated display: true option can still build a DisplayReactor, so the class and zod stay in the bundle. When that option is removed at the next major, defineReactor drops to about 60 kB minified, 17.6 kB gzipped. Until then, an app that wants the smallest bundle and has no use for DisplayReactor sets up with createActorHooks(new Reactor(...)) (the Quick Start above) and createAuthHooks.

Both define* functions also include the identity-attribute code (about 6 kB minified, 1.8 kB gzipped) whether or not the app calls useIdentityAttributes, because it is part of the object they return.

useIdentityAttributes() comes from createIdentityAttributeHooks(), a factory separate from createAuthHooks(). It returns the helpers for requesting signed OpenID email and profile attributes:

import {
AuthenticationManager,
IdentityAttributesManager,
createIdentityAttributeHooks,
} from "@ic-reactor/react"
// The `clientManager` and `backend` the Quick Start's module exports
import { backend, clientManager } from "./reactor"
const authentication = new AuthenticationManager({ clientManager })
const identityAttributes = new IdentityAttributesManager(authentication)
const { useIdentityAttributes } =
createIdentityAttributeHooks(identityAttributes)
function ContinueWithProvider() {
const { requestOpenIdAttributes, isRequestingAttributes } =
useIdentityAttributes()
async function handleClick() {
const result = await requestOpenIdAttributes({
// Pass the nonce as a callback: awaiting it first ends the user gesture
// and the browser blocks the Internet Identity window.
nonce: () => backend.callMethod({ functionName: "register_begin" }),
openIdProvider: "microsoft",
keys: ["email", "name"],
})
await backend.callMethod({
functionName: "register_finish",
args: [
{
data: result.signedAttributes.data,
signature: result.signedAttributes.signature,
},
],
})
}
return (
<button disabled={isRequestingAttributes} onClick={handleClick}>
Continue with provider
</button>
)
}

Provider aliases ("google", "apple", and "microsoft") and full issuer URLs are supported. Always verify the signed payload server-side or in your canister before trusting decoded values.

  • Queries — Standard query patterns
  • Mutations — Update and invalidation patterns
  • Authentication — Internet Identity and identity attributes
  • Query Caching — Cache behavior and invalidation
  • Testing — Component and hook tests against a fake replica, with @ic-reactor/react/testing
  • @ic-reactor/core — Runtime layer re-exported by this package