Skip to content

React Hooks

HieroKit includes an optional React layer that wraps the core client and flows with ergonomic hooks. The React APIs are built on top of the same HieroKit client – there is no separate network stack.

Installation

React support is bundled in the main package:

bash
npm install hierokit @hiero-ledger/sdk react react-dom

The library declares react as a peer dependency so you can manage the exact version in your app.

HieroProvider

At the root of your app, provide a configured Hiero client:

tsx
import { HieroProvider } from "hierokit";

const config = {
  network: "testnet" as const,
  operator: {
    accountId: process.env.HEDERA_ACCOUNT_ID as string,
    privateKey: process.env.HEDERA_PRIVATE_KEY as string,
  },
  mirrorNodeUrl: "https://testnet.mirrornode.hedera.com",
};

export function AppRoot() {
  return (
    <HieroProvider config={config}>
      <App />
    </HieroProvider>
  );
}

All hooks below assume they are used inside HieroProvider.

Core environment hooks

These come from the react/core module and are re‑exported from hierokit:

  • useHieroClient() – access the configured Client wrapper
  • useHieroConfig() – read the current HieroConfig
  • useNetwork() – convenience for config.network
  • useLedgerId() – read client.raw.ledgerId
  • useNodeList() – list of network nodes
  • useClientStatus()"idle" or "ready"
  • useClientHealth()"ready" or "unknown"
  • useMirrorNodeUrl() – resolved mirror REST base URL or null
  • useMaxTransactionFee() – default max transaction fee (Hbar | null)
  • useDefaultOperator() – current operator information

Example:

tsx
import { useNetwork, useHieroClient } from "hierokit";

function NetworkBadge() {
  const network = useNetwork();
  const client = useHieroClient();

  return (
    <div>
      <div>Network: {typeof network === "string" ? network : "custom"}</div>
      <div>Operator: {client.raw.operatorAccountId?.toString() ?? "none"}</div>
    </div>
  );
}

Transaction flows in React

The core DX primitive is a flow – a function that takes a HieroKit Client and returns a Promise of a receipt or other result:

ts
type TransactionFlow<TReceipt = TransactionReceipt> =
  (client: Client) => Promise<TReceipt>;

The useTransactionFlow hook manages the lifecycle:

tsx
import {
  useTransactionFlow,
  type TransactionFlow,
} from "hierokit";

const transferFlow: TransactionFlow = async (client) => {
  const handle = await client.transferHbar("0.0.xxxx", 10, "Hello HieroKit");
  const receipt = await handle.wait();
  return receipt;
};

function TransferButton() {
  const flow = useTransactionFlow(transferFlow, {
    autoStart: false,
    timeoutMs: 60_000,
  });

  return (
    <div>
      <button onClick={() => flow.start()} disabled={flow.status === "submitting"}>
        Transfer
      </button>

      {flow.status === "success" && (
        <p>Done: {flow.receipt?.status.toString()}</p>
      )}
      {flow.status === "error" && <p>Error: {String(flow.error)}</p>}
    </div>
  );
}

Supporting helpers:

  • useCreateFlow(intent, options?) – same as useTransactionFlow but never auto‑starts
  • useFlowStatus(handle) – read FlowStatus
  • useFlowReceipt(handle) – read the flow result
  • useFlowError(handle) – read the last error
  • useRetryFlow(handle) – retry the same flow
  • useCancelFlow(handle) – cancel an in‑flight flow
  • useFlowTimeout(handle) – read the configured timeout

This is the React counterpart of HieroKit’s declarative flow model: the intent is a pure function, and the hook handles retries, cancellation and timeout.

Account & identity hooks

Account hooks follow a consistent pattern:

  • data – the normalized result (for example a Hbar, map, or DTO)
  • status"idle" | "loading" | "success" | "error"
  • error – error from the latest request
  • refresh() – re‑run the underlying query

If accountId is omitted, the hooks default to the configured operator account.

useAccountId()

Resolve the current account ID:

tsx
import { useAccountId } from "hierokit";

const CurrentAccount = () => {
  const accountId = useAccountId();
  return <span>{accountId?.toString() ?? "no operator"}</span>;
};

useAccountInfo(accountId?)

Query full AccountInfo:

tsx
import { useAccountInfo } from "hierokit";

function AccountInfoPanel() {
  const { data, status, error } = useAccountInfo();

  if (status === "loading") return <p>Loading...</p>;
  if (status === "error") return <p>Error: {String(error)}</p>;
  if (!data) return null;

  return (
    <div>
      <div>ID: {data.accountId.toString()}</div>
      <div>Memo: {data.accountMemo}</div>
    </div>
  );
}

useAccountBalance(accountId?) and useAccountHbarBalance(accountId?)

Access the full balance or just the HBAR portion:

tsx
import { useAccountHbarBalance } from "hierokit";

function HbarBalance() {
  const { data: hbar, status } = useAccountHbarBalance();

  if (status !== "success" || !hbar) return <span>Loading...</span>;
  return <span>{hbar.toString()}</span>;
}

useAccountTokens(accountId?)

Token balances for fungible tokens:

tsx
import { useAccountTokens } from "hierokit";

function TokenList() {
  const { data: tokens, status } = useAccountTokens();
  if (status !== "success" || !tokens) return null;

  return (
    <ul>
      {Array.from(tokens.entries()).map(([tokenId, balance]) => (
        <li key={tokenId.toString()}>
          {tokenId.toString()}: {balance.toString()}
        </li>
      ))}
    </ul>
  );
}

useAccountNFTs(accountId?)

Fetch NFTs for an account via the configured mirror node:

tsx
import { useAccountNFTs } from "hierokit";

function NFTGrid() {
  const { data, status, error } = useAccountNFTs();

  if (status === "loading") return <p>Loading NFTs...</p>;
  if (status === "error") return <p>Error: {String(error)}</p>;
  if (!data) return <p>No NFTs</p>;

  return (
    <ul>
      {data.map((nft, i) => (
        <li key={i}>{JSON.stringify(nft)}</li>
      ))}
    </ul>
  );
}

This requires mirrorNodeUrl to be set in HieroConfig.

Other account helpers

All derived from AccountInfo:

  • useAccountKeys(accountId?)
  • useAccountStakingInfo(accountId?)
  • useAccountMemo(accountId?)
  • useIsAccountDeleted(accountId?)
  • useIsAccountFrozen(accountId?)
  • useAccountExpiration(accountId?)
  • useAccountAutoRenew(accountId?)
  • useAccountProxy(accountId?)
  • useAccountLedgerId(accountId?)

These are thin selectors over the raw SDK response, keeping your components focused on rendering and user flows instead of query plumbing.