TanStack Router
A full-featured application demonstrating IC Reactor with TanStack Router for navigation, route loaders, and authentication.
Features Demonstrated
Section titled “Features Demonstrated”- Retargeting one reactor per route with
setCanisterId()in aloader - Generated
createQuery/createSuspenseQuery/createSuspenseQueryFactory/createMutationmodules, one per method - Suspense-based data fetching with
<Suspense>boundaries - Query invalidation after mutations with
reactor.invalidateQueries() - Authentication with
createAuthHooks - File-based routing structure
Open in StackBlitzEdit and run in your browser
View on GitHubBrowse the source code
Live Preview
Section titled “Live Preview”Key Code
Section titled “Key Code”One Shared Reactor
Section titled “One Shared Reactor”A single DisplayReactor is defined once and retargeted per route, so every
generated query object keeps working when the user switches tokens:
import { DisplayReactor, createActorHooks } from "@ic-reactor/react"import { clientManager } from "../../lib/client"import { idlFactory, type _SERVICE } from "./declarations/icrc1.did"
export type LedgerService = _SERVICE
export const ledgerReactor = new DisplayReactor<LedgerService>({ clientManager, idlFactory, name: "ledger", canisterId: "ryjl3-tyaaa-aaaaa-aaaba-cai",})
export const { useActorQuery, useActorMutation, useActorSuspenseQuery } = createActorHooks(ledgerReactor)Route Loader
Section titled “Route Loader”The loader points the shared reactor at the canister for this route. Query keys are rooted at the reactor’s canister ID, so every cached entry is scoped automatically:
// src/routes/wallet/$canisterId.tsximport { createFileRoute } from "@tanstack/react-router"import { ledgerReactor } from "@/canisters/ledger/reactor"
export const Route = createFileRoute("/wallet/$canisterId")({ component: TokenWallet, loader: async ({ params: { canisterId } }) => { ledgerReactor.setCanisterId(canisterId) },})
function TokenWallet() { // Refresh every query for the active canister const handleRefreshAll = () => ledgerReactor.invalidateQueries() // ...}Per-Method Query Modules
Section titled “Per-Method Query Modules”Generated hook modules wrap the reactor in reusable query objects, usable both inside components and in loaders:
import { createQuery } from "@ic-reactor/react"import { ledgerReactor } from "../reactor"
export const icrc1NameQuery = createQuery(ledgerReactor, { functionName: "icrc1_name",})import { icrc1NameQuery } from "@/canisters/ledger/hooks"
export function TokenName() { const { data: name } = icrc1NameQuery.useQuery() return <span>{name ?? "Token"}</span>}