Open
Description
Check existing issues
- I checked there isn't already an issue for the bug I encountered.
Describe the bug
When using useWatchBlocks
with a WebSocket connection, the expected behavior is as follows:
- Subscribe to new blocks
- Receive (
onBlock
) callbacks without unsubscribing - Unsubscribe when the component using
useWatchBlocks
is unmounted / modified
The observed behavior is:
- Subscribe to new heads
- Receive a block, execute
onBlock
- Unsubscribe as a dependency seems to change in the implementation of
useWatchBlocks
, probably caused byuseEffect
in theuseWatchBlocks
implementation - Re-Subscribe and repeat
It's important to be aware that subscribing / Unsubscribing can be an expensive call on certain API providers (e.g. 10 Compute Units on Alchemy), causing unnecessary spikes in API Usage.
Link to Minimal Reproducible Example
No response
Steps To Reproduce
- Configure Wagmi with a WebSocket RPC endpoint
- Use the snippets below, which only slightly modify the
useWatchBlocks
code to get console log outputs
You will observe that the subscription is closed after each block, and a new subscription is established.
Code to use the modified hook:
useWatchBlocks({
emitOnBegin: true,
chainId: Constants.CHAIN_ID,
onBlock: (b) => {
console.log(b)
}
})
The modified hook:
'use client'
import {
type Config,
type ResolvedRegister,
type WatchBlocksParameters,
watchBlocks,
} from '@wagmi/core'
import type { UnionCompute, UnionExactPartial } from '@wagmi/core/internal'
import { useEffect } from 'react'
import type { BlockTag } from 'viem'
// Import wagmi config and constants for test
import { config } from '../AppKit'
export type EnabledParameter = {
enabled?: boolean | undefined
}
export type ConfigParameter<config extends Config = Config> = {
config?: Config | config | undefined
}
export type UseWatchBlocksParameters<
includeTransactions extends boolean = false,
blockTag extends BlockTag = 'latest',
config extends Config = Config,
chainId extends
config['chains'][number]['id'] = config['chains'][number]['id'],
> = UnionCompute<
UnionExactPartial<
WatchBlocksParameters<includeTransactions, blockTag, config, chainId>
> &
ConfigParameter<config> &
EnabledParameter
>
export type UseWatchBlocksReturnType = void
/** https://wagmi.sh/react/hooks/useWatchBlocks */
export function useWatchBlocks<
config extends Config = ResolvedRegister['config'],
chainId extends
config['chains'][number]['id'] = config['chains'][number]['id'],
includeTransactions extends boolean = false,
blockTag extends BlockTag = 'latest',
>(
parameters: UseWatchBlocksParameters<
includeTransactions,
blockTag,
config,
chainId
> = {} as any,
): UseWatchBlocksReturnType {
const { enabled = true, onBlock, config: _, ...rest } = parameters
const chainId = parameters.chainId
// TODO(react@19): cleanup
// biome-ignore lint/correctness/useExhaustiveDependencies: `rest` changes every render so only including properties in dependency array
useEffect(() => {
if (!enabled) return
if (!onBlock) return
// Slightly modify for console logs
console.log('WATCH')
const unwatch = watchBlocks(config, {
...(rest as any),
chainId,
onBlock,
})
return () => {
console.log('UNWATCH')
unwatch()
}
}, [
chainId,
config,
enabled,
onBlock,
///
rest.blockTag,
rest.emitMissed,
rest.emitOnBegin,
rest.includeTransactions,
rest.onError,
rest.poll,
rest.pollingInterval,
rest.syncConnectedChain,
])
}
What Wagmi package(s) are you using?
wagmi
Wagmi Package(s) Version(s)
2.12.17
Viem Version
2.21.21
TypeScript Version
5.6.0
Anything else?
No response