0
# React Hooks
1
2
React hooks for accessing Web3 state and functionality from any component within a Web3ConfigProvider context.
3
4
## Capabilities
5
6
### useAccount
7
8
Hook to access the current connected account information including address, name, avatar, and connection status.
9
10
```typescript { .api }
11
/**
12
* Hook to access the current connected account information
13
* @returns Object containing account information
14
*/
15
function useAccount(): Pick<ConfigConsumerProps, 'account'>;
16
17
interface ConfigConsumerProps {
18
account?: Account;
19
}
20
21
interface Account {
22
address: string;
23
name?: string;
24
avatar?: string;
25
addresses?: [`0x${string}`, ...`0x${string}`[]] | readonly `0x${string}`[];
26
status?: ConnectStatus;
27
}
28
29
const enum ConnectStatus {
30
Connected = 'connected',
31
Disconnected = 'disconnected',
32
Signed = 'signed',
33
}
34
```
35
36
**Usage Examples:**
37
38
```typescript
39
import { useAccount } from "@ant-design/web3";
40
41
function AccountDisplay() {
42
const { account } = useAccount();
43
44
if (!account) {
45
return <div>No account connected</div>;
46
}
47
48
return (
49
<div>
50
<h3>Connected Account</h3>
51
<p>Address: {account.address}</p>
52
{account.name && <p>Name: {account.name}</p>}
53
<p>Status: {account.status}</p>
54
{account.avatar && (
55
<img src={account.avatar} alt="Avatar" width={32} height={32} />
56
)}
57
{account.addresses && (
58
<div>
59
<h4>Multiple Addresses:</h4>
60
<ul>
61
{account.addresses.map((addr, index) => (
62
<li key={index}>{addr}</li>
63
))}
64
</ul>
65
</div>
66
)}
67
</div>
68
);
69
}
70
71
// Conditional rendering based on connection status
72
function ConditionalContent() {
73
const { account } = useAccount();
74
75
switch (account?.status) {
76
case 'connected':
77
return <div>Wallet connected: {account.address}</div>;
78
case 'signed':
79
return <div>Wallet signed in: {account.address}</div>;
80
case 'disconnected':
81
default:
82
return <div>Please connect your wallet</div>;
83
}
84
}
85
86
// Using account in effects
87
function AccountWatcher() {
88
const { account } = useAccount();
89
90
useEffect(() => {
91
if (account?.address) {
92
console.log('Account changed:', account.address);
93
// Fetch user data, update UI, etc.
94
fetchUserData(account.address);
95
}
96
}, [account?.address]);
97
98
return <div>Watching account changes...</div>;
99
}
100
```
101
102
### useConnection
103
104
Hook to access wallet connection and disconnection functions for programmatic wallet management.
105
106
```typescript { .api }
107
/**
108
* Hook to access wallet connection and disconnection functions
109
* @returns Object containing connect and disconnect functions
110
*/
111
function useConnection(): Pick<ConfigConsumerProps, 'connect' | 'disconnect'>;
112
113
interface ConfigConsumerProps {
114
connect?: (wallet?: Wallet, options?: ConnectOptions) => Promise<void | Account>;
115
disconnect?: () => Promise<void>;
116
}
117
118
interface ConnectOptions {
119
connectType?: 'extension' | 'qrCode' | 'openMobile';
120
}
121
122
interface Wallet extends WalletMetadata {
123
_standardWallet?: any;
124
_isMobileWallet?: boolean;
125
hasWalletReady?: () => Promise<boolean>;
126
hasExtensionInstalled?: () => Promise<boolean>;
127
getQrCode?: () => Promise<{ uri: string }>;
128
customQrCodePanel?: boolean;
129
}
130
```
131
132
**Usage Examples:**
133
134
```typescript
135
import { useConnection } from "@ant-design/web3";
136
137
function CustomConnectButton() {
138
const { connect, disconnect } = useConnection();
139
const { account } = useAccount();
140
141
const handleConnect = async () => {
142
try {
143
const result = await connect();
144
console.log('Connected:', result);
145
} catch (error) {
146
console.error('Connection failed:', error);
147
}
148
};
149
150
const handleDisconnect = async () => {
151
try {
152
await disconnect();
153
console.log('Disconnected successfully');
154
} catch (error) {
155
console.error('Disconnection failed:', error);
156
}
157
};
158
159
if (account) {
160
return (
161
<button onClick={handleDisconnect}>
162
Disconnect {account.address}
163
</button>
164
);
165
}
166
167
return (
168
<button onClick={handleConnect}>
169
Connect Wallet
170
</button>
171
);
172
}
173
174
// Connect to specific wallet
175
function WalletSpecificConnect() {
176
const { connect } = useConnection();
177
178
const connectToMetaMask = async () => {
179
const metaMaskWallet = {
180
name: "MetaMask",
181
remark: "Connect with MetaMask",
182
icon: "metamask-icon",
183
extensions: [{
184
key: 'Chrome',
185
browserIcon: 'chrome',
186
browserName: 'Chrome',
187
link: 'https://metamask.io',
188
description: 'MetaMask extension'
189
}]
190
};
191
192
try {
193
await connect(metaMaskWallet, { connectType: 'extension' });
194
} catch (error) {
195
console.error('MetaMask connection failed:', error);
196
}
197
};
198
199
return <button onClick={connectToMetaMask}>Connect MetaMask</button>;
200
}
201
202
// Connection with loading state
203
function ConnectWithLoading() {
204
const { connect, disconnect } = useConnection();
205
const { account } = useAccount();
206
const [loading, setLoading] = useState(false);
207
208
const handleConnect = async () => {
209
setLoading(true);
210
try {
211
await connect();
212
} catch (error) {
213
console.error('Connection error:', error);
214
} finally {
215
setLoading(false);
216
}
217
};
218
219
return (
220
<button onClick={handleConnect} disabled={loading}>
221
{loading ? 'Connecting...' : account ? 'Connected' : 'Connect'}
222
</button>
223
);
224
}
225
```
226
227
### useProvider
228
229
Hook to access the complete Web3 provider context with optional prop overrides for customization and testing.
230
231
```typescript { .api }
232
/**
233
* Hook to access the Web3 provider context with optional prop overrides
234
* @param props - Optional props to override context values
235
* @returns Complete provider interface with merged context and props
236
*/
237
function useProvider(
238
props?: UniversalWeb3ProviderInterface
239
): UniversalWeb3ProviderInterface;
240
241
interface UniversalWeb3ProviderInterface {
242
account?: Account;
243
chain?: Chain;
244
balance?: Balance;
245
availableWallets?: Wallet[];
246
availableChains?: Chain[];
247
extendsContextFromParent?: boolean;
248
addressPrefix?: string | false;
249
connect?: (wallet?: Wallet, options?: ConnectOptions) => Promise<void | Account>;
250
disconnect?: () => Promise<void>;
251
switchChain?: (chain: Chain) => Promise<void>;
252
getNFTMetadata?: (params: { address: string; tokenId?: bigint }) => Promise<NFTMetadata>;
253
sign?: SignConfig;
254
}
255
256
interface Balance {
257
value?: bigint;
258
coverAddress?: boolean;
259
name?: string;
260
symbol?: string;
261
icon?: React.ReactNode;
262
decimal?: number;
263
}
264
265
interface Chain {
266
id: ChainIds | number;
267
name: string;
268
type?: ChainType;
269
icon?: React.ReactNode;
270
browser?: {
271
icon?: React.ReactNode;
272
getBrowserLink?: (address: string, type: BrowserLinkType) => string;
273
};
274
nativeCurrency?: BalanceMetadata & { name: string };
275
}
276
```
277
278
**Usage Examples:**
279
280
```typescript
281
import { useProvider } from "@ant-design/web3";
282
283
// Access full provider context
284
function ProviderInfo() {
285
const provider = useProvider();
286
287
return (
288
<div>
289
<h3>Provider Information</h3>
290
<p>Current Chain: {provider.chain?.name}</p>
291
<p>Account: {provider.account?.address}</p>
292
<p>Balance: {provider.balance?.value?.toString()}</p>
293
<p>Available Wallets: {provider.availableWallets?.length}</p>
294
<p>Available Chains: {provider.availableChains?.length}</p>
295
</div>
296
);
297
}
298
299
// Override provider values
300
function CustomProvider() {
301
const customChain = {
302
id: 1337,
303
name: "Local Testnet",
304
type: ChainType.EVM
305
};
306
307
const provider = useProvider({
308
chain: customChain,
309
addressPrefix: "local:"
310
});
311
312
return (
313
<div>
314
<p>Using custom chain: {provider.chain?.name}</p>
315
<p>Address prefix: {provider.addressPrefix}</p>
316
</div>
317
);
318
}
319
320
// Chain switching functionality
321
function ChainSwitcher() {
322
const provider = useProvider();
323
324
const switchToPolygon = async () => {
325
const polygonChain = {
326
id: 137,
327
name: "Polygon",
328
type: ChainType.EVM
329
};
330
331
try {
332
await provider.switchChain?.(polygonChain);
333
console.log('Switched to Polygon');
334
} catch (error) {
335
console.error('Chain switch failed:', error);
336
}
337
};
338
339
return (
340
<div>
341
<p>Current: {provider.chain?.name}</p>
342
<button onClick={switchToPolygon}>Switch to Polygon</button>
343
</div>
344
);
345
}
346
347
// NFT metadata fetching
348
function NFTLoader() {
349
const provider = useProvider();
350
const [metadata, setMetadata] = useState(null);
351
352
const loadNFT = async () => {
353
if (provider.getNFTMetadata) {
354
try {
355
const nftData = await provider.getNFTMetadata({
356
address: "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d",
357
tokenId: BigInt(1)
358
});
359
setMetadata(nftData);
360
} catch (error) {
361
console.error('NFT load failed:', error);
362
}
363
}
364
};
365
366
return (
367
<div>
368
<button onClick={loadNFT}>Load NFT</button>
369
{metadata && <p>NFT Name: {metadata.name}</p>}
370
</div>
371
);
372
}
373
```
374
375
### useNFT
376
377
Hook for loading NFT metadata with automatic caching, loading states, and error handling.
378
379
```typescript { .api }
380
/**
381
* Hook for loading NFT metadata
382
* @param address - NFT contract address
383
* @param tokenId - NFT token ID
384
* @param getNFTMetadata - Custom metadata fetcher function
385
* @returns Object containing loading state, metadata, and error
386
*/
387
function useNFT(
388
address?: string,
389
tokenId?: bigint | number,
390
getNFTMetadata?: Web3ConfigProviderProps['getNFTMetadata']
391
): { loading: boolean; metadata: NFTMetadata; error?: Error };
392
393
interface NFTMetadata {
394
name?: string;
395
description?: string;
396
image?: string;
397
dna?: string;
398
edition?: string | number;
399
date?: number;
400
attributes?: Array<{
401
trait_type?: string;
402
value?: string;
403
}>;
404
compiler?: string;
405
}
406
```
407
408
**Usage Examples:**
409
410
```typescript
411
import { useNFT } from "@ant-design/web3";
412
413
// Basic NFT loading
414
function NFTDisplay() {
415
const { loading, metadata, error } = useNFT(
416
"0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d",
417
BigInt(1)
418
);
419
420
if (loading) return <div>Loading NFT...</div>;
421
if (error) return <div>Error: {error.message}</div>;
422
423
return (
424
<div>
425
<h3>{metadata.name}</h3>
426
<p>{metadata.description}</p>
427
{metadata.image && (
428
<img src={metadata.image} alt={metadata.name} width={300} />
429
)}
430
{metadata.attributes && (
431
<div>
432
<h4>Attributes:</h4>
433
{metadata.attributes.map((attr, index) => (
434
<div key={index}>
435
{attr.trait_type}: {attr.value}
436
</div>
437
))}
438
</div>
439
)}
440
</div>
441
);
442
}
443
444
// Dynamic NFT loading with state
445
function DynamicNFTViewer() {
446
const [contractAddress, setContractAddress] = useState("");
447
const [tokenId, setTokenId] = useState("");
448
449
const { loading, metadata, error } = useNFT(
450
contractAddress || undefined,
451
tokenId ? BigInt(tokenId) : undefined
452
);
453
454
return (
455
<div>
456
<input
457
placeholder="Contract Address"
458
value={contractAddress}
459
onChange={(e) => setContractAddress(e.target.value)}
460
/>
461
<input
462
placeholder="Token ID"
463
value={tokenId}
464
onChange={(e) => setTokenId(e.target.value)}
465
/>
466
467
{loading && <div>Loading...</div>}
468
{error && <div>Error: {error.message}</div>}
469
{metadata.name && (
470
<div>
471
<h3>{metadata.name}</h3>
472
{metadata.image && <img src={metadata.image} width={200} />}
473
</div>
474
)}
475
</div>
476
);
477
}
478
479
// Custom metadata fetcher
480
function CustomNFTLoader() {
481
const customFetcher = async ({ address, tokenId }) => {
482
const response = await fetch(`/api/nft/${address}/${tokenId}`);
483
if (!response.ok) throw new Error('Failed to fetch NFT');
484
return response.json();
485
};
486
487
const { loading, metadata, error } = useNFT(
488
"0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d",
489
BigInt(1234),
490
customFetcher
491
);
492
493
return (
494
<div>
495
{loading ? "Loading..." : metadata.name || "No NFT data"}
496
</div>
497
);
498
}
499
500
// NFT with fallback handling
501
function RobustNFTDisplay() {
502
const { loading, metadata, error } = useNFT(
503
"0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d",
504
BigInt(9999)
505
);
506
507
if (loading) {
508
return (
509
<div className="nft-loading">
510
<div className="spinner" />
511
<span>Loading NFT metadata...</span>
512
</div>
513
);
514
}
515
516
if (error) {
517
return (
518
<div className="nft-error">
519
<h4>Failed to load NFT</h4>
520
<p>{error.message}</p>
521
<button onClick={() => window.location.reload()}>
522
Retry
523
</button>
524
</div>
525
);
526
}
527
528
return (
529
<div className="nft-card">
530
<img
531
src={metadata.image || '/placeholder-nft.png'}
532
alt={metadata.name || 'NFT'}
533
onError={(e) => {
534
e.target.src = '/placeholder-nft.png';
535
}}
536
/>
537
<h3>{metadata.name || 'Unnamed NFT'}</h3>
538
<p>{metadata.description || 'No description available'}</p>
539
</div>
540
);
541
}
542
```
543
544
## Hook Integration Patterns
545
546
### Combined Hook Usage
547
548
```typescript
549
import { useAccount, useConnection, useProvider } from "@ant-design/web3";
550
551
function WalletManager() {
552
const { account } = useAccount();
553
const { connect, disconnect } = useConnection();
554
const provider = useProvider();
555
556
const handleChainSwitch = async (chainId: number) => {
557
const targetChain = provider.availableChains?.find(
558
chain => chain.id === chainId
559
);
560
561
if (targetChain && provider.switchChain) {
562
await provider.switchChain(targetChain);
563
}
564
};
565
566
return (
567
<div>
568
{account ? (
569
<div>
570
<p>Connected: {account.address}</p>
571
<p>Chain: {provider.chain?.name}</p>
572
<button onClick={() => disconnect()}>Disconnect</button>
573
<select onChange={(e) => handleChainSwitch(Number(e.target.value))}>
574
{provider.availableChains?.map(chain => (
575
<option key={chain.id} value={chain.id}>{chain.name}</option>
576
))}
577
</select>
578
</div>
579
) : (
580
<button onClick={() => connect()}>Connect Wallet</button>
581
)}
582
</div>
583
);
584
}
585
```
586
587
### Testing with Hooks
588
589
```typescript
590
import { renderHook } from '@testing-library/react';
591
import { useProvider } from "@ant-design/web3";
592
593
// Test hook with mock data
594
const wrapper = ({ children }) => (
595
<Web3ConfigProvider
596
account={{ address: "0x123", status: "connected" }}
597
chain={{ id: 1, name: "Ethereum" }}
598
>
599
{children}
600
</Web3ConfigProvider>
601
);
602
603
const { result } = renderHook(() => useProvider(), { wrapper });
604
expect(result.current.account?.address).toBe("0x123");
605
```