Web3 钱包连接:MetaMask 与 DApp 交互(React)
·
Web3 钱包连接:MetaMask 与 DApp 交互(React)
1. 核心概念
- MetaMask:浏览器扩展钱包,提供以太坊账户管理和区块链交互接口。
- DApp:去中心化应用,通过智能合约与区块链交互。
- 交互流程:
graph LR A[DApp前端] -->|请求连接| B[MetaMask] B -->|授权账户| A A -->|调用合约| C[以太坊网络]
2. 环境准备
安装必要依赖:
npm install ethers @metamask/detect-provider
3. 连接钱包实现
步骤 1:检测 MetaMask 提供者
import { useState, useEffect } from 'react';
import { ethers } from 'ethers';
const useMetaMask = () => {
const [account, setAccount] = useState(null);
const [provider, setProvider] = useState(null);
useEffect(() => {
const initProvider = async () => {
if (window.ethereum) {
const provider = new ethers.providers.Web3Provider(window.ethereum);
setProvider(provider);
// 检查是否已连接
const accounts = await provider.listAccounts();
if (accounts.length > 0) setAccount(accounts[0]);
}
};
initProvider();
}, []);
return { account, provider, connectWallet };
};
步骤 2:连接钱包函数
const connectWallet = async () => {
if (!window.ethereum) {
alert('请安装MetaMask!');
return;
}
try {
const accounts = await window.ethereum.request({
method: 'eth_requestAccounts'
});
setAccount(accounts[0]);
} catch (error) {
console.error('连接失败:', error);
}
};
4. UI 集成示例
function WalletButton() {
const { account, connectWallet } = useMetaMask();
return (
<button onClick={connectWallet}>
{account ? `已连接: ${account.slice(0,6)}...` : '连接MetaMask'}
</button>
);
}
5. 合约交互示例
调用 ERC-20 代币余额:
const getTokenBalance = async (tokenAddress) => {
if (!provider || !account) return;
const contract = new ethers.Contract(
tokenAddress,
['function balanceOf(address) view returns (uint256)'],
provider
);
const balance = await contract.balanceOf(account);
return ethers.utils.formatUnits(balance, 18); // 假设18位小数
};
6. 事件监听
处理账户切换:
useEffect(() => {
if (!window.ethereum) return;
const handleAccountsChanged = (accounts) => {
setAccount(accounts[0] || null);
};
window.ethereum.on('accountsChanged', handleAccountsChanged);
return () => window.ethereum.removeListener('accountsChanged', handleAccountsChanged);
}, []);
7. 安全注意事项
- 交易确认:关键操作需用户二次确认
const sendTransaction = async () => { await window.ethereum.request({ method: 'eth_sendTransaction', params: [{ from: account, to: '0x...', value: '0x...' }] }); }; - 网络验证:检查是否正确网络
const chainId = await window.ethereum.request({ method: 'eth_chainId' }); if (chainId !== '0x1') alert('请切换到主网!');
8. 完整组件示例
export default function DAppInterface() {
const { account, provider } = useMetaMask();
const [balance, setBalance] = useState(0);
useEffect(() => {
if (account && provider) {
provider.getBalance(account).then(bal => {
setBalance(ethers.utils.formatEther(bal));
});
}
}, [account, provider]);
return (
<div>
<WalletButton />
{account && (
<div>
<p>ETH 余额: ${balance}$</p>
<button onClick={sendTransaction}>发送交易</button>
</div>
)}
</div>
);
}
9. 常见问题解决
| 问题 | 解决方案 |
|---|---|
| 连接无响应 | 检查 MetaMask 弹窗是否被浏览器拦截 |
| 交易失败 | 确保账户有足够 ETH 支付 gas 费 |
| 网络错误 | 使用 window.ethereum.request({ method: 'wallet_switchEthereumChain' }) 切换网络 |
最佳实践:
- 使用
@metamask/sdk优化移动端兼容性- 关键操作添加加载状态提示
- 在用户断开钱包后清理本地缓存数据
通过此实现,React DApp 可安全连接 MetaMask,实现账户管理、资产查询和链上交易功能。
更多推荐



所有评论(0)