React中useState无法更新currentAccount,Metamask场景下方案失效
问题分析与修复方案
核心问题点
useEffect依赖引发重复执行与事件重复绑定
你的useEffect依赖了walletConnected和currentAccount,每次这两个状态更新都会重新触发useEffect并调用onPageLoad,导致accountsChanged事件被多次绑定,引发状态更新混乱。同时setCurrentAccount是异步操作,在connectWallet后立即调用getUserRole,大概率拿到的还是旧的currentAccount值。事件监听器未做清理
组件卸载时没有移除accountsChanged的监听器,容易造成内存泄漏或不必要的重复触发。
修复步骤
1. 调整初始化逻辑,避免重复执行
将初始化改为仅在组件挂载时执行一次,同时添加事件监听器的清理逻辑:
useEffect(() => { const initWallet = async () => { if (!walletConnected) { await connectWallet(); // 定义账户变化处理函数 const handleAccountsChanged = (accounts) => { setCurrentAccount(accounts[0]); }; // 绑定事件监听器 window.ethereum.on('accountsChanged', handleAccountsChanged); // 组件卸载时移除监听器,防止内存泄漏 return () => { window.ethereum.removeListener('accountsChanged', handleAccountsChanged); }; } }; initWallet(); }, [walletConnected]); // 仅当walletConnected状态变化时触发,或用空数组仅在组件挂载时执行
2. 分离getUserRole调用逻辑
让getUserRole自动响应currentAccount变化,无需手动在多个地方调用:
useEffect(() => { // 仅当currentAccount存在时调用 if (currentAccount) { getUserRole(); } }, [currentAccount]); // 依赖currentAccount,状态更新时自动执行
3. 优化connectWallet函数(可选)
添加日志确认账户获取状态,确保accounts数组有效:
const connectWallet = async () => { try { const provider = await getProviderOrSigner(); const accounts = await provider.send("eth_requestAccounts", []); // 检查账户是否获取成功 if (!accounts || accounts.length === 0) { console.error("未获取到有效账户"); return; } setCurrentAccount(accounts[0]); setWalletConnected(true); return provider; } catch (error) { console.error("连接钱包失败:", error); } };
4. 移除冗余的onPageLoad调用
将原onPageLoad中的逻辑整合到上述initWallet函数中,避免重复执行带来的问题。
额外检查点
- 确认
getProviderOrSigner函数能正确返回MetaMask的provider,无异常。 - 检查组件中
currentAccount的初始值是否为'',保证状态更新逻辑正常。
内容的提问来源于stack exchange,提问作者asusrid
相关产品推荐
相关产品推荐

