or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

account-chain-state.mdadvanced-features.mdblockchain-data-reading.mdconfiguration.mdconnection-management.mdcontract-interactions.mdens-operations.mdevent-watching.mdindex.mdsigning-verification.mdtanstack-query.mdtransaction-management.md

tanstack-query.mddocs/

0

# TanStack Query Integration

1

2

First-class TanStack Query support with query options, mutation options, and caching strategies.

3

4

## Overview

5

6

@wagmi/core provides comprehensive TanStack Query integration through the `/query` export. This integration offers optimized caching, background refetching, and reactive data management for all blockchain operations.

7

8

## Core Query Functions

9

10

### Query Options for Read Operations

11

12

Generate TanStack Query options for read operations that automatically handle caching and refetching.

13

14

```typescript { .api }

15

/**

16

* Query options for balance queries

17

* @param config - Wagmi configuration

18

* @param options - Balance query options

19

* @returns TanStack Query options

20

*/

21

function getBalanceQueryOptions<config extends Config>(

22

config: config,

23

options: GetBalanceOptions<config>

24

): QueryOptions<GetBalanceData, GetBalanceErrorType>;

25

26

interface GetBalanceOptions<config extends Config> {

27

/** Account address */

28

address: Address;

29

/** Token contract address (optional) */

30

token?: Address;

31

/** Chain ID */

32

chainId?: config['chains'][number]['id'];

33

/** Query configuration */

34

query?: {

35

enabled?: boolean;

36

staleTime?: number;

37

gcTime?: number;

38

};

39

}

40

41

type GetBalanceData = {

42

decimals: number;

43

formatted: string;

44

symbol: string;

45

value: bigint;

46

};

47

48

/**

49

* Query key for balance queries

50

* @param parameters - Balance parameters

51

* @returns Query key array

52

*/

53

function getBalanceQueryKey(parameters?: GetBalanceParameters): GetBalanceQueryKey;

54

55

type GetBalanceQueryKey = readonly ['balance', GetBalanceParameters];

56

57

type GetBalanceQueryFnData = GetBalanceReturnType;

58

```

59

60

**Usage Example:**

61

62

```typescript

63

import { useQuery } from '@tanstack/react-query'

64

import { getBalanceQueryOptions } from '@wagmi/core/query'

65

66

// In React component

67

function BalanceDisplay({ address }: { address: Address }) {

68

const { data: balance, isLoading, error } = useQuery(

69

getBalanceQueryOptions(config, {

70

address,

71

query: {

72

staleTime: 1000 * 60, // 1 minute

73

enabled: !!address,

74

},

75

})

76

)

77

78

if (isLoading) return <div>Loading balance...</div>

79

if (error) return <div>Error loading balance</div>

80

if (!balance) return null

81

82

return (

83

<div>

84

Balance: {balance.formatted} {balance.symbol}

85

</div>

86

)

87

}

88

89

// In vanilla JavaScript

90

import { QueryClient } from '@tanstack/query-core'

91

92

const queryClient = new QueryClient()

93

94

const balance = await queryClient.fetchQuery(

95

getBalanceQueryOptions(config, {

96

address: '0x742d35Cc6601C2F3Ac5e5c7A9d16e4e6Be4e6e9e',

97

})

98

)

99

console.log('Balance:', balance.formatted)

100

```

101

102

### Contract Read Query Options

103

104

Query options for contract read operations.

105

106

```typescript { .api }

107

/**

108

* Query options for contract reads

109

* @param config - Wagmi configuration

110

* @param options - Contract read options

111

* @returns TanStack Query options

112

*/

113

function readContractQueryOptions<config extends Config>(

114

config: config,

115

options: ReadContractOptions<config>

116

): QueryOptions<ReadContractData, ReadContractErrorType>;

117

118

interface ReadContractOptions<config extends Config> {

119

/** Contract address */

120

address: Address;

121

/** Contract ABI */

122

abi: Abi;

123

/** Function name */

124

functionName: string;

125

/** Function arguments */

126

args?: readonly unknown[];

127

/** Chain ID */

128

chainId?: config['chains'][number]['id'];

129

/** Query configuration */

130

query?: {

131

enabled?: boolean;

132

staleTime?: number;

133

gcTime?: number;

134

};

135

}

136

137

type ReadContractData = any; // Depends on contract function

138

139

/**

140

* Query key for contract reads

141

* @param parameters - Contract read parameters

142

* @returns Query key array

143

*/

144

function readContractQueryKey(parameters?: ReadContractParameters): ReadContractQueryKey;

145

146

type ReadContractQueryKey = readonly ['readContract', ReadContractParameters];

147

148

/**

149

* Query options for multiple contract reads

150

* @param config - Wagmi configuration

151

* @param options - Multiple contract read options

152

* @returns TanStack Query options

153

*/

154

function readContractsQueryOptions<config extends Config>(

155

config: config,

156

options: ReadContractsOptions<config>

157

): QueryOptions<ReadContractsData, ReadContractsErrorType>;

158

159

interface ReadContractsOptions<config extends Config> {

160

/** Array of contract calls */

161

contracts: readonly {

162

address: Address;

163

abi: Abi;

164

functionName: string;

165

args?: readonly unknown[];

166

}[];

167

/** Chain ID */

168

chainId?: config['chains'][number]['id'];

169

/** Allow failures */

170

allowFailure?: boolean;

171

/** Query configuration */

172

query?: {

173

enabled?: boolean;

174

staleTime?: number;

175

gcTime?: number;

176

};

177

}

178

179

type ReadContractsData = ReadContractsReturnType;

180

```

181

182

**Usage Example:**

183

184

```typescript

185

import { useQuery } from '@tanstack/react-query'

186

import { readContractQueryOptions } from '@wagmi/core/query'

187

188

// Single contract read

189

function TokenName({ address }: { address: Address }) {

190

const { data: name } = useQuery(

191

readContractQueryOptions(config, {

192

address,

193

abi: erc20Abi,

194

functionName: 'name',

195

query: {

196

staleTime: 1000 * 60 * 60, // 1 hour (name rarely changes)

197

},

198

})

199

)

200

201

return <div>Token: {name}</div>

202

}

203

204

// Multiple contract reads

205

function TokenInfo({ address }: { address: Address }) {

206

const { data: tokenData } = useQuery(

207

readContractsQueryOptions(config, {

208

contracts: [

209

{ address, abi: erc20Abi, functionName: 'name' },

210

{ address, abi: erc20Abi, functionName: 'symbol' },

211

{ address, abi: erc20Abi, functionName: 'decimals' },

212

{ address, abi: erc20Abi, functionName: 'totalSupply' },

213

],

214

})

215

)

216

217

if (!tokenData) return null

218

219

return (

220

<div>

221

<div>Name: {tokenData[0].result}</div>

222

<div>Symbol: {tokenData[1].result}</div>

223

<div>Decimals: {tokenData[2].result}</div>

224

<div>Total Supply: {tokenData[3].result?.toString()}</div>

225

</div>

226

)

227

}

228

```

229

230

### Blockchain Data Query Options

231

232

Query options for blockchain data like blocks, transactions, and network information.

233

234

```typescript { .api }

235

/**

236

* Query options for block data

237

* @param config - Wagmi configuration

238

* @param options - Block query options

239

* @returns TanStack Query options

240

*/

241

function getBlockQueryOptions<config extends Config>(

242

config: config,

243

options: GetBlockOptions<config>

244

): QueryOptions<GetBlockData, GetBlockErrorType>;

245

246

interface GetBlockOptions<config extends Config> {

247

/** Block number */

248

blockNumber?: bigint;

249

/** Block hash */

250

blockHash?: Hash;

251

/** Block tag */

252

blockTag?: 'latest' | 'earliest' | 'pending' | 'safe' | 'finalized';

253

/** Include transactions */

254

includeTransactions?: boolean;

255

/** Chain ID */

256

chainId?: config['chains'][number]['id'];

257

/** Query configuration */

258

query?: {

259

enabled?: boolean;

260

staleTime?: number;

261

gcTime?: number;

262

};

263

}

264

265

type GetBlockData = GetBlockReturnType;

266

267

/**

268

* Query options for block number

269

* @param config - Wagmi configuration

270

* @param options - Block number options

271

* @returns TanStack Query options

272

*/

273

function getBlockNumberQueryOptions<config extends Config>(

274

config: config,

275

options: GetBlockNumberOptions<config>

276

): QueryOptions<GetBlockNumberData, GetBlockNumberErrorType>;

277

278

interface GetBlockNumberOptions<config extends Config> {

279

/** Chain ID */

280

chainId?: config['chains'][number]['id'];

281

/** Query configuration */

282

query?: {

283

enabled?: boolean;

284

staleTime?: number;

285

gcTime?: number;

286

refetchInterval?: number; // Auto-refetch for latest block

287

};

288

}

289

290

type GetBlockNumberData = bigint;

291

292

/**

293

* Query options for transaction data

294

* @param config - Wagmi configuration

295

* @param options - Transaction query options

296

* @returns TanStack Query options

297

*/

298

function getTransactionQueryOptions<config extends Config>(

299

config: config,

300

options: GetTransactionOptions<config>

301

): QueryOptions<GetTransactionData, GetTransactionErrorType>;

302

303

interface GetTransactionOptions<config extends Config> {

304

/** Transaction hash */

305

hash: Hash;

306

/** Chain ID */

307

chainId?: config['chains'][number]['id'];

308

/** Query configuration */

309

query?: {

310

enabled?: boolean;

311

staleTime?: number;

312

gcTime?: number;

313

};

314

}

315

316

type GetTransactionData = GetTransactionReturnType;

317

318

/**

319

* Query options for transaction receipt

320

* @param config - Wagmi configuration

321

* @param options - Transaction receipt options

322

* @returns TanStack Query options

323

*/

324

function getTransactionReceiptQueryOptions<config extends Config>(

325

config: config,

326

options: GetTransactionReceiptOptions<config>

327

): QueryOptions<GetTransactionReceiptData, GetTransactionReceiptErrorType>;

328

329

interface GetTransactionReceiptOptions<config extends Config> {

330

/** Transaction hash */

331

hash: Hash;

332

/** Chain ID */

333

chainId?: config['chains'][number]['id'];

334

/** Query configuration */

335

query?: {

336

enabled?: boolean;

337

staleTime?: number;

338

gcTime?: number;

339

};

340

}

341

342

type GetTransactionReceiptData = GetTransactionReceiptReturnType;

343

```

344

345

### Additional Query Options

346

347

Additional blockchain operations and client query options.

348

349

```typescript { .api }

350

/**

351

* Query options for arbitrary contract calls

352

* @param config - Wagmi configuration

353

* @param options - Call options

354

* @returns TanStack Query options

355

*/

356

function callQueryOptions<config extends Config>(

357

config: config,

358

options: CallOptions<config>

359

): QueryOptions<CallData, CallErrorType>;

360

361

/**

362

* Query options for Merkle proofs

363

* @param config - Wagmi configuration

364

* @param options - Proof options

365

* @returns TanStack Query options

366

*/

367

function getProofQueryOptions<config extends Config>(

368

config: config,

369

options: GetProofOptions<config>

370

): QueryOptions<GetProofData, GetProofErrorType>;

371

372

/**

373

* Query options for connector clients

374

* @param config - Wagmi configuration

375

* @param options - Connector client options

376

* @returns TanStack Query options

377

*/

378

function getConnectorClientQueryOptions<config extends Config>(

379

config: config,

380

options: GetConnectorClientOptions<config>

381

): QueryOptions<GetConnectorClientData, GetConnectorClientErrorType>;

382

383

/**

384

* Query options for wallet clients

385

* @param config - Wagmi configuration

386

* @param options - Wallet client options

387

* @returns TanStack Query options

388

*/

389

function getWalletClientQueryOptions<config extends Config>(

390

config: config,

391

options: GetWalletClientOptions<config>

392

): QueryOptions<GetWalletClientData, GetWalletClientErrorType>;

393

```

394

395

## Mutation Options for Write Operations

396

397

Generate TanStack Query mutation options for write operations like transactions and contract interactions.

398

399

```typescript { .api }

400

/**

401

* Mutation options for sending transactions

402

* @param config - Wagmi configuration

403

* @returns TanStack Query mutation options

404

*/

405

function sendTransactionMutationOptions<config extends Config>(

406

config: config

407

): MutationOptions<SendTransactionData, SendTransactionErrorType, SendTransactionVariables>;

408

409

interface SendTransactionVariables {

410

/** Target address */

411

to?: Address;

412

/** Transaction data */

413

data?: Hex;

414

/** Gas limit */

415

gas?: bigint;

416

/** Gas price */

417

gasPrice?: bigint;

418

/** Max fee per gas */

419

maxFeePerGas?: bigint;

420

/** Max priority fee per gas */

421

maxPriorityFeePerGas?: bigint;

422

/** Nonce */

423

nonce?: number;

424

/** Value to send */

425

value?: bigint;

426

/** Chain ID */

427

chainId?: number;

428

}

429

430

type SendTransactionData = Hash;

431

432

type SendTransactionMutate = (variables: SendTransactionVariables) => void;

433

type SendTransactionMutateAsync = (variables: SendTransactionVariables) => Promise<SendTransactionData>;

434

435

/**

436

* Mutation options for contract writes

437

* @param config - Wagmi configuration

438

* @returns TanStack Query mutation options

439

*/

440

function writeContractMutationOptions<config extends Config>(

441

config: config

442

): MutationOptions<WriteContractData, WriteContractErrorType, WriteContractVariables>;

443

444

interface WriteContractVariables {

445

/** Contract address */

446

address: Address;

447

/** Contract ABI */

448

abi: Abi;

449

/** Function name */

450

functionName: string;

451

/** Function arguments */

452

args?: readonly unknown[];

453

/** Chain ID */

454

chainId?: number;

455

/** Gas options */

456

gas?: bigint;

457

gasPrice?: bigint;

458

maxFeePerGas?: bigint;

459

maxPriorityFeePerGas?: bigint;

460

/** Transaction value */

461

value?: bigint;

462

}

463

464

type WriteContractData = Hash;

465

466

type WriteContractMutate = (variables: WriteContractVariables) => void;

467

type WriteContractMutateAsync = (variables: WriteContractVariables) => Promise<WriteContractData>;

468

469

/**

470

* Mutation options for wallet connection

471

* @param config - Wagmi configuration

472

* @returns TanStack Query mutation options

473

*/

474

function connectMutationOptions<config extends Config>(

475

config: config

476

): MutationOptions<ConnectData, ConnectErrorType, ConnectVariables>;

477

478

interface ConnectVariables {

479

/** Connector to connect with */

480

connector: Connector | CreateConnectorFn;

481

/** Chain ID to connect to */

482

chainId?: number;

483

}

484

485

type ConnectData = {

486

accounts: readonly [Address, ...Address[]];

487

chainId: number;

488

};

489

490

type ConnectMutate = (variables: ConnectVariables) => void;

491

type ConnectMutateAsync = (variables: ConnectVariables) => Promise<ConnectData>;

492

```

493

494

**Usage Example:**

495

496

```typescript

497

import { useMutation, useQueryClient } from '@tanstack/react-query'

498

import { sendTransactionMutationOptions, getBalanceQueryKey } from '@wagmi/core/query'

499

500

function SendTransactionButton() {

501

const queryClient = useQueryClient()

502

503

const {

504

mutate: sendTransaction,

505

mutateAsync: sendTransactionAsync,

506

isPending,

507

error,

508

} = useMutation({

509

...sendTransactionMutationOptions(config),

510

onSuccess: (hash) => {

511

console.log('Transaction sent:', hash)

512

// Invalidate balance queries to refetch

513

queryClient.invalidateQueries({

514

queryKey: getBalanceQueryKey(),

515

})

516

},

517

})

518

519

const handleSend = () => {

520

sendTransaction({

521

to: '0x742d35Cc6601C2F3Ac5e5c7A9d16e4e6Be4e6e9e',

522

value: parseEther('0.1'),

523

})

524

}

525

526

const handleSendAsync = async () => {

527

try {

528

const hash = await sendTransactionAsync({

529

to: '0x742d35Cc6601C2F3Ac5e5c7A9d16e4e6Be4e6e9e',

530

value: parseEther('0.1'),

531

})

532

console.log('Transaction sent:', hash)

533

} catch (error) {

534

console.error('Transaction failed:', error)

535

}

536

}

537

538

return (

539

<div>

540

<button onClick={handleSend} disabled={isPending}>

541

{isPending ? 'Sending...' : 'Send Transaction'}

542

</button>

543

<button onClick={handleSendAsync} disabled={isPending}>

544

Send Async

545

</button>

546

{error && <div>Error: {error.message}</div>}

547

</div>

548

)

549

}

550

```

551

552

## Advanced Query Options

553

554

### Infinite Queries

555

556

For paginated data like contract events or transaction lists.

557

558

```typescript { .api }

559

/**

560

* Infinite query options for contract reads

561

* @param config - Wagmi configuration

562

* @param options - Infinite query options

563

* @returns TanStack Query infinite options

564

*/

565

function infiniteReadContractsQueryOptions<config extends Config>(

566

config: config,

567

options: InfiniteReadContractsOptions<config>

568

): InfiniteQueryOptions<InfiniteReadContractsData, InfiniteReadContractsErrorType>;

569

570

interface InfiniteReadContractsOptions<config extends Config> {

571

/** Array of contract calls with pagination */

572

contracts: (pageParam: unknown) => readonly {

573

address: Address;

574

abi: Abi;

575

functionName: string;

576

args?: readonly unknown[];

577

}[];

578

/** Chain ID */

579

chainId?: config['chains'][number]['id'];

580

/** Query configuration */

581

query?: {

582

enabled?: boolean;

583

staleTime?: number;

584

gcTime?: number;

585

getNextPageParam?: (lastPage: any, allPages: any[]) => unknown;

586

getPreviousPageParam?: (firstPage: any, allPages: any[]) => unknown;

587

};

588

}

589

590

type InfiniteReadContractsData = {

591

pages: ReadContractsReturnType[];

592

pageParams: unknown[];

593

};

594

595

type InfiniteReadContractsQueryKey = readonly ['infiniteReadContracts', InfiniteReadContractsOptions];

596

597

type InfiniteReadContractsQueryFnData = ReadContractsReturnType;

598

```

599

600

### Query Utilities

601

602

Utility functions for working with query keys and caching.

603

604

```typescript { .api }

605

/**

606

* Hash function for query keys

607

* @param queryKey - Query key to hash

608

* @returns Hash string

609

*/

610

function hashFn(queryKey: QueryKey): string;

611

612

/**

613

* Structural sharing for query data

614

* @param oldData - Previous data

615

* @param newData - New data

616

* @returns Optimized data with structural sharing

617

*/

618

function structuralSharing<T>(oldData: T | undefined, newData: T): T;

619

620

type QueryKey = readonly unknown[];

621

```

622

623

**Usage Example:**

624

625

```typescript

626

import { hashFn, structuralSharing } from '@wagmi/core/query'

627

628

// Custom query with optimized caching

629

const customQueryOptions = {

630

queryKey: ['custom', 'data'],

631

queryFn: async () => {

632

// Fetch data

633

return await fetchCustomData()

634

},

635

select: (data: any) => structuralSharing(undefined, data),

636

queryKeyHashFn: hashFn,

637

}

638

639

// Use with QueryClient

640

const queryClient = new QueryClient({

641

defaultOptions: {

642

queries: {

643

queryKeyHashFn: hashFn,

644

structuralSharing,

645

},

646

},

647

})

648

```

649

650

## Complete Integration Example

651

652

Here's a comprehensive example showing how to use TanStack Query with wagmi:

653

654

```typescript

655

import { QueryClient, useQuery, useMutation, useQueryClient } from '@tanstack/react-query'

656

import {

657

getBalanceQueryOptions,

658

readContractQueryOptions,

659

writeContractMutationOptions,

660

getBalanceQueryKey,

661

} from '@wagmi/core/query'

662

663

// Set up QueryClient with wagmi optimizations

664

const queryClient = new QueryClient({

665

defaultOptions: {

666

queries: {

667

staleTime: 1000 * 60, // 1 minute

668

gcTime: 1000 * 60 * 60 * 24, // 24 hours

669

},

670

},

671

})

672

673

// React component example

674

function TokenManager({ tokenAddress, userAddress }: {

675

tokenAddress: Address

676

userAddress: Address

677

}) {

678

const queryClient = useQueryClient()

679

680

// Query user's token balance

681

const { data: balance, isLoading: balanceLoading } = useQuery(

682

getBalanceQueryOptions(config, {

683

address: userAddress,

684

token: tokenAddress,

685

query: {

686

enabled: !!userAddress && !!tokenAddress,

687

staleTime: 1000 * 30, // 30 seconds for balance

688

},

689

})

690

)

691

692

// Query token metadata

693

const { data: tokenName } = useQuery(

694

readContractQueryOptions(config, {

695

address: tokenAddress,

696

abi: erc20Abi,

697

functionName: 'name',

698

query: {

699

enabled: !!tokenAddress,

700

staleTime: 1000 * 60 * 60, // 1 hour for token name

701

},

702

})

703

)

704

705

// Mutation for token transfer

706

const {

707

mutate: transfer,

708

isPending: transferPending,

709

error: transferError,

710

} = useMutation({

711

...writeContractMutationOptions(config),

712

onSuccess: (hash) => {

713

console.log('Transfer successful:', hash)

714

715

// Invalidate and refetch balance

716

queryClient.invalidateQueries({

717

queryKey: getBalanceQueryKey({ address: userAddress, token: tokenAddress }),

718

})

719

720

// Optimistically update balance (optional)

721

queryClient.setQueryData(

722

getBalanceQueryKey({ address: userAddress, token: tokenAddress }),

723

(oldBalance: any) => {

724

if (!oldBalance) return oldBalance

725

return {

726

...oldBalance,

727

value: oldBalance.value - transferAmount, // Subtract transferred amount

728

formatted: formatUnits(oldBalance.value - transferAmount, oldBalance.decimals),

729

}

730

}

731

)

732

},

733

onError: (error) => {

734

console.error('Transfer failed:', error)

735

},

736

})

737

738

const handleTransfer = (to: Address, amount: bigint) => {

739

transfer({

740

address: tokenAddress,

741

abi: erc20Abi,

742

functionName: 'transfer',

743

args: [to, amount],

744

})

745

}

746

747

if (balanceLoading) return <div>Loading...</div>

748

749

return (

750

<div>

751

<h3>{tokenName}</h3>

752

<p>Balance: {balance?.formatted} {balance?.symbol}</p>

753

754

<button

755

onClick={() => handleTransfer('0xRecipient', parseUnits('10', balance?.decimals || 18))}

756

disabled={transferPending}

757

>

758

{transferPending ? 'Transferring...' : 'Transfer 10 tokens'}

759

</button>

760

761

{transferError && (

762

<div>Error: {transferError.message}</div>

763

)}

764

</div>

765

)

766

}

767

768

// App setup

769

function App() {

770

return (

771

<QueryClientProvider client={queryClient}>

772

<TokenManager

773

tokenAddress="0xA0b86a33E6411c0B7f8C4b5d3e1B9d3e8b4a4e6f"

774

userAddress="0x742d35Cc6601C2F3Ac5e5c7A9d16e4e6Be4e6e9e"

775

/>

776

</QueryClientProvider>

777

)

778

}

779

```

780

781

This integration provides:

782

- Automatic caching and background refetching

783

- Optimistic updates for better UX

784

- Query invalidation after mutations

785

- Type safety with wagmi's typed functions

786

- Efficient data fetching and synchronization