Skip to content

This tutorial walks you through creating your first IC Reactor integration with React. We’ll use the Vite Plugin to automate declaration generation and hook creation, which is the recommended way to use IC Reactor.

  1. Terminal window
    pnpm add @ic-reactor/react @icp-sdk/core @tanstack/react-query
    pnpm add -D @ic-reactor/vite-plugin
  2. Add the plugin to your vite.config.ts. This will automatically generate TypeScript declarations and React hooks whenever you modify your .did file.

    vite.config.ts
    import { icReactorPlugin } from "@ic-reactor/vite-plugin"
    export default defineConfig({
    plugins: [
    icReactorPlugin({
    canisters: [
    {
    name: "backend",
    didFile: "src/backend/backend.did",
    },
    ],
    }),
    ],
    })
  3. Create a central ClientManager. The generated reactors will use this by default.

    src/clients.ts
    import { ClientManager } from "@ic-reactor/react"
    import { QueryClient } from "@tanstack/react-query"
    export const queryClient = new QueryClient()
    export const clientManager = new ClientManager({
    queryClient,
    withCanisterEnv: true, // Enable cookie-based env injection
    })
  4. Import the generated hooks directly from your declarations folder. They are fully typed and ready to use!

    src/components/Greeting.tsx
    import { useBackendQuery } from "../declarations/backend"
    function Greeting() {
    const { data, isPending, error } = useBackendQuery({
    functionName: "greet",
    args: ["World"],
    })
    if (isPending) return <div>Loading...</div>
    if (error) return <div>Error: {error.message}</div>
    return <h1>{data}</h1>
    }
  5. Mutations are also generated automatically:

    src/components/Counter.tsx
    import { useBackendQuery, useBackendMutation } from "../declarations/backend"
    function Counter() {
    const { data: count } = useBackendQuery({ functionName: "getCount" })
    const { mutate, isPending } = useBackendMutation({
    functionName: "increment",
    onSuccess: () => {
    // The generated reactor provides helper to invalidate queries
    // ... custom invalidation logic here
    },
    })
    return (
    <div>
    <p>Count: {count ?? "..."}</p>
    <button onClick={() => mutate([])} disabled={isPending}>
    {isPending ? "Incrementing..." : "Increment"}
    </button>
    </div>
    )
    }

Using the Vite plugin provides several advantages out-of-the-box:

  • Zero-config Proxy: /api requests are automatically proxied to your local replica.
  • Auto-Canister IDs: Canister IDs are automatically detected from your local network (via icp or dfx).
  • Identity Support: Works seamlessly with local Internet Identity setups.

The plugin handles environment variables for you in development. For production, you might still want to set canister IDs in your environment file:

Terminal window
# .env.local (for Vite)
VITE_BACKEND_CANISTER_ID=rrkah-fqaaa-aaaaa-aaaaq-cai

You now have IC Reactor working! Here’s what to explore next: