use-truapi
Contracts

useContractQuery

Read-only contract call, a ReviveApi dry-run cached like any query

useContractQuery performs a read-only contract call: a ReviveApi.call dry-run that never signs or submits anything. data is the decoded return value; pass the expected type as the generic (useContractQuery<bigint>(…)). Results are cached under the contract identity, the method name and the args, so several components reading the same value share one dry-run; different args are different cache entries.

While the contract handle hasn't resolved the query stays disabled (isPending), no need to guard on the handle. If the call reverts the query errors with contract query "method" reverted and the revert value attached as error.cause; an unknown method name errors with contract has no method "method".

Reads are one shot, not subscriptions. Call refetch() (for example from a transaction's onSuccess) to observe a new value after a write.

Usage

import { useContract, useContractQuery } from "@use-truapi/react";
import { COUNTER_LIBRARY, cdmJson } from "./counter-contract";

function Count() {
  const contract = useContract(cdmJson, COUNTER_LIBRARY);
  const count = useContractQuery<bigint>(contract.data, "getCount", []);

  if (count.isPending) return <p>Reading count…</p>;
  if (count.error) return <p>Read failed: {count.error.message}</p>;

  return (
    <p>
      Count: {count.data.toString()}{" "}
      <button type="button" onClick={() => count.refetch()}>Refresh</button>
    </p>
  );
}

In React, pass the resolved handle, contract.data, as the first argument.

<script setup lang="ts">
import { useContract, useContractQuery } from "@use-truapi/vue";
import { COUNTER_LIBRARY, cdmJson } from "./counter-contract";

const contract = useContract(cdmJson, COUNTER_LIBRARY);
const count = useContractQuery<bigint>(contract, "getCount", []);
</script>

<template>
  <p v-if="count.isPending">Reading count…</p>
  <p v-else-if="count.error">Read failed: {{ count.error.message }}</p>
  <p v-else>
    Count: {{ count.data?.toString() }}
    <button type="button" @click="count.refetch()">Refresh</button>
  </p>
</template>

In Vue, pass the whole query result returned by useContract or useContractAt; the read unwraps contract.data reactively and enables itself once the handle resolves. Args may be a getter (() => [props.id]) so reactive args re-run the read.

Gate the read with enabled while an input is incomplete; it combines with the built-in "contract resolved" gate:

const balance = useContractQuery<bigint>(contract.data, "balanceOf", [owner], {
  enabled: owner !== undefined, // Vue: () => owner.value !== undefined
});

See also

API reference

React

function useContractQuery<T>(
   contract, 
   method, 
   args, 
options?): UseQueryResult<T, Error>;

Read-only contract call (ReviveApi.call dry-run) — cached under the contract identity, method and args.

const count = useContractQuery(contract, "getCount", []);

Type Parameters

Type ParameterDefault type
Tunknown

Parameters

ParameterType
contract| Contract<ContractDef> | undefined
methodstring
argsreadonly unknown[]
options?{ enabled?: boolean; query?: QueryOptions<T>; }
options.enabled?boolean
options.query?QueryOptions<T>

Returns

UseQueryResult<T, Error>

Vue

function useContractQuery<T>(
   contract, 
   method, 
   args?, 
options?): QueryResult<T>;

Read-only contract call (ReviveApi.call dry-run) — cached under the contract identity, method and args; reactive args re-run it.

Type Parameters

Type ParameterDefault type
Tunknown

Parameters

ParameterTypeDefault value
contractQueryResult<Contract<ContractDef>>undefined
methodstringundefined
argsMaybeGetter<readonly unknown[]>[]
options?{ enabled?: MaybeGetter<boolean>; query?: QueryOptions<T>; }undefined
options.enabled?MaybeGetter<boolean>undefined
options.query?QueryOptions<T>undefined

Returns

QueryResult<T>

On this page