useTrackedData

function useTrackedData<TRpcValue, TSubscriptionValue, TItem>(
    spec,
    options?,
): TrackedDataResult<TItem>;

Render reactive state for an RPC subscription seeded by a one-shot RPC fetch, slot-deduped. The subscription (e.g. accountNotifications) is the primary source of live updates; the initial fetch (e.g. getBalance) provides a value to surface as soon as it resolves — typically before the first subscription notification arrives — so the loading paint is shorter than subscription-only would give you. The underlying store slot-dedupes between the two sources — out-of-order arrivals never regress the surfaced value.

Pass a memoized TrackedDataSpec keyed on whatever inputs it depends on; stable identity is how the hook knows when to tear down and re-run. Pass null to gate the work off — the result reports status: 'disabled'.

SSR-safe — on the server the connect effect doesn't run, so the store stays idle and the hook reports status: 'loading'. The first client render hydrates from that same loading paint, then commits the connect effect.

Type Parameters

Type ParameterDescription
TRpcValueThe value inside the initial RPC SolanaRpcResponse envelope.
TSubscriptionValueThe value inside subscription SolanaRpcResponse notifications.
TItemThe unified item type produced by the two mappers and stored in the result.

Parameters

ParameterType
spec| Readonly<{ rpcRequest: RpcSendable<Readonly<{ context: Readonly<{ slot: Slot; }>; value: TRpcValue; }>>; rpcSubscriptionRequest: RpcSubscribable<Readonly<{ context: Readonly<{ slot: Slot; }>; value: TSubscriptionValue; }>>; rpcSubscriptionValueMapper: (value) => TItem; rpcValueMapper: (value) => TItem; }> | null
options?UseTrackedDataOptions

Returns

TrackedDataResult<TItem>

Example

function AccountBalance({ address }: { address: Address }) {
    const client = useClient<ClientWithRpc<GetBalanceApi> & ClientWithRpcSubscriptions<AccountNotificationsApi>>();
    const spec = useMemo(() => ({
        rpcRequest: client.rpc.getBalance(address),
        rpcSubscriptionRequest: client.rpcSubscriptions.accountNotifications(address),
        rpcValueMapper: (lamports: bigint) => lamports,
        rpcSubscriptionValueMapper: ({ lamports }: { lamports: bigint }) => lamports,
    }), [client, address]);
    const { data, error, refresh } = useTrackedData(spec);
    if (error) return <button onClick={refresh}>Retry</button>;
    return <p>{data ? `${data.value} lamports at slot ${data.context.slot}` : 'Loading…'}</p>;
}

See

On this page