use-truapi
Chain

useChainQuery

One-shot read against the typed api, cached by chain and deps

useChainQuery runs a one-shot read against the typed PAPI api. The deps array identifies the read: change a dep and it re-runs and is cached separately. Two components reading with the same chain and deps share one result. Deps are serialized bigint-safely, so bigint values are fine.

The value is fetched once; it does not update as new blocks arrive. For values that should track the chain head use useChainSubscription. To refresh a read, call refetch() on the result.

While enabled is false nothing is fetched and the result stays pending, so you can depend on data that may not exist yet (an unconnected wallet, an unresolved route param) without guarding the callback.

Usage

import { useChainQuery, useSelectedAccount } from "@use-truapi/react";

function AccountInfo() {
  const account = useSelectedAccount();
  const address = account?.address;

  // `address` is a dep: the read re-runs (and caches separately) per address.
  const { data, isPending, error } = useChainQuery(
    (api) => api.query.System.Account.getValue(address!),
    [address],
    { enabled: address !== undefined },
  );

  if (!account) return <p>Connect a wallet first.</p>;
  if (isPending) return <p>Loading account…</p>;
  if (error) return <p>Failed to read account: {error.message}</p>;

  return (
    <p>
      Nonce {data.nonce}, free {data.data.free.toString()} planck
    </p>
  );
}
<script setup lang="ts">
import { useChainQuery, useSelectedAccount } from "@use-truapi/vue";

const account = useSelectedAccount();

// Deps are getters: the read re-runs when the address changes.
const { data, isPending, error } = useChainQuery(
  (api) => api.query.System.Account.getValue(account.value!.address),
  [() => account.value?.address],
  { enabled: () => account.value !== undefined },
);
</script>

<template>
  <p v-if="!account">Connect a wallet first.</p>
  <p v-else-if="isPending">Loading account…</p>
  <p v-else-if="error">Failed to read account: {{ error.message }}</p>
  <p v-else>Nonce {{ data.nonce }}, free {{ data.data.free }} planck</p>
</template>

Pass getters in deps (and for enabled) so the read follows the reactive value when it changes.

A read with no inputs takes an empty deps array and is cached once per chain:

const totalIssuance = useChainQuery(
  (api) => api.query.Balances.TotalIssuance.getValue(),
  [],
);

To read another chain, pass its key; the read callback is then typed against that chain's descriptor:

const { data } = useChainQuery(
  (api) => api.query.Identity.IdentityOf.getValue(address!),
  [address],
  { chain: "people", enabled: address !== undefined },
);

See also

API reference

React

function useChainQuery<T, K>(
   read, 
   deps, 
options?): UseQueryResult<T, Error>;

One-shot read against the typed api, cached under queryKeys.chainQuery(chain, deps)deps are part of the query key, so the read re-runs (and caches separately) when they change.

const total = useChainQuery((api) => api.query.Balances.TotalIssuance.getValue(), []);

Type Parameters

Type ParameterDefault type
T-
K extends stringstring

Parameters

ParameterType
read(api) => Promise<T>
depsreadonly unknown[]
options?ChainScope<K> & object

Returns

UseQueryResult<T, Error>

Vue

function useChainQuery<T, K>(
   read, 
   deps?, 
options?): QueryResult<T>;

One-shot read against the typed api, cached under queryKeys.chainQuery(chain, deps). Pass getters in deps for reactive inputs — they become part of the query key, so the read re-runs (and caches separately) when they change.

Type Parameters

Type ParameterDefault type
T-
K extends stringstring

Parameters

ParameterTypeDefault value
read(api) => Promise<T>undefined
depsreadonly unknown[][]
options?ChainScope<K> & objectundefined

Returns

QueryResult<T>

On this page