2.0 RC docsView 1.x docs
Concept · Read-hook query options

Tune any product read hook with query

Every product read hook takes TanStack's cache options as query, while the hook keeps the key and fetcher.

v2.0.0-rc.1 release candidate
The API is frozen and later candidates carry fixes only, except the receipt-free and Safe create surface of /fhe-airdrop, which is @beta. Published on the next dist-tag; latest stays on 1.6.0 until 2.0.0.

ReadHookQueryOptions#

The /fhe-airdrop read hooks took a query option first. The /fhe-vesting, /fhe-disperse and /testnet-faucet read hooks now take the same option, typed ReadHookQueryOptions and exported from each of those react subpaths.

import type { UseQueryOptions } from "@tanstack/react-query";

interface ReadHookQueryOptions<TData = unknown> {
  /** TanStack Query options for this read, minus queryKey and queryFn. */
  query?: Omit<UseQueryOptions<TData, Error>, "queryKey" | "queryFn">;
}

queryKey and queryFn stay owned by the hook, so cache identity never drifts from what was fetched. Everything else (staleTime, gcTime, refetchInterval, placeholderData and so on) passes through.

import { useIsRegistered } from "@tokenops/sdk/fhe-disperse/react";

const { data: isRegistered } = useIsRegistered({
  user,
  query: {
    refetchInterval: 10_000,
    enabled: panelOpen, // can turn a ready query off, never an unready one on
  },
});

enabled is combined, not replaced#

Each hook has its own readiness: a resolved client, a connected public client, the arguments it needs. query.enabled is combined with that readiness. It can turn a ready query off; it can never turn an unready one on, so enabled: truedoes not make a hook fetch without its address. The caller's value is passed through rather than coerced, so TanStack's function form of enabled keeps working.

select keeps the result type#

query.select is typed (data: TData) => TData on every product, so the hook result stays TData. Use it to normalize a value; derive a different shape from data at the call site rather than casting a reshaping selector.

import { getAddress } from "viem";
import { useManagerToken } from "@tokenops/sdk/fhe-vesting/react";

// select is (data: Address) => Address here: normalize, do not reshape.
const { data: token } = useManagerToken({
  address: manager,
  query: { select: (t) => getAddress(t) },
});
const label = token ? shortAddress(token) : undefined; // derive other shapes here

Reads that default to staleTime: Infinity#

Reads of values baked into bytecode or fixed at create time default to staleTime: Infinity. Pass query: { staleTime: 0 } to opt out. The list below is taken from the hook code itself, not the TSDoc, checked against the installed 2.0.0-rc.1 build. Every other read defaults to staleTime: 0.

SubpathRead hooksDefault staleTime: InfinityInfinity once positive
@tokenops/sdk/fhe-vesting/react29useManagerToken, useManagerFeeType, useManagerFee, useManagerFeeInfo, useManagerDeploymentBlockNumber, useManagerIsSplitEnabled, useManagerIsPausable, useRoleConstantsnone
@tokenops/sdk/fhe-vesting/advanced/react1nonenone
@tokenops/sdk/fhe-airdrop/react33useAirdropConfig, useAirdropDeploymentMode, useAirdropRoleAdmin, useAirdropRoleConstants, useComplianceRoleConstants, useDedupMode, useEcdsaDomain, useIsMerkleRootMutable, useUnwrapRequestuseIsAirdrop, useComplianceManagerOf, useTokenOf
@tokenops/sdk/fhe-airdrop/advanced/react12useFactoryRoleConstantsnone
@tokenops/sdk/fhe-disperse/react13useDeploymentBlockNumber, useWalletImplementationnone
@tokenops/sdk/testnet-faucet/react9useFaucetRate, useFaucetDecimals, useUnderlyingDecimals, useUnderlyingTokenAddress, useMaxTotalSupply, useFaucetMetadatanone

useIsOperator is the exception#

useIsOperator lives in /fhe/react and is re-exported by the vesting and disperse react subpaths. It takes a plain enabled and chainId, not a query object.

See also