You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React setState状态更新失效 无法获取链上账户余额

React类组件setState不更新、链上余额无法渲染修复方案

核心问题原因

  • setState本身是异步批量执行的,你在loadWeb3Data中连续调用三次setState存储合约实例后,立刻同步调用fetchAccountInfo,此时React还未完成状态更新,this.state.daiContract、this.state.ethers仍然是初始化的null值,调用balanceOf方法会直接抛出异常,后续更新余额的逻辑根本不会执行,页面始终显示初始的walletBalance: "5"。
  • 使用了React已标记为废弃、存在执行时序风险的componentWillMount生命周期做异步请求,在React18版本中该方法的执行逻辑会导致状态更新异常。
  • 直接在setState调用后同步打印this.state,本身就只能拿到更新前的旧状态,属于React异步更新的正常机制,不是bug。
  • 初始化合约实例时未传入签名者,部分RPC节点会拦截关联当前钱包地址的查询请求,返回异常数据。

修复步骤

  1. 替换废弃生命周期
    删除原有的componentWillMount,使用React官方推荐的副作用执行生命周期componentDidMount:
componentDidMount() {
  this.loadWindow()
}
  1. 调整状态更新时序,避开异步读旧值问题
    不要在调用setState后立刻从this.state读取刚设置的值,合约实例初始化后先存在局部变量中,直接传入fetchAccountInfo使用,等链上数据查询完成后再批量更新状态,避免时序问题:
async loadWeb3Data(){
  // 原有ABI定义部分保持不变
  const provider=new providers.Web3Provider(window.ethereum)
  const signer = provider.getSigner() // 获取签名者,兼容后续合约写入操作
  window.alert("Start")
  // 合约实例先存局部变量,不立即setState
  const daiContract=new Contract("0x6B175474E89094C44Da98b954EedeAC495271d0F",daiAbi,signer);
  const cDaiContract= new Contract("0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643",cDaiAbi,signer)
  const AaveLendingPoolContract=new Contract("0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9",AaveLendingPoolAbi,signer)

  // 直接把需要的参数传入方法,不依赖this.state的即时更新
  await this.fetchAccountInfo({
    daiContract,
    defaultAccount: this.state.defaultAccount,
    ethersIns: ethers
  })

  // 数据查询完成后批量更新合约实例到state
  this.setState({
    daiContract,
    cDaiContract,
    AaveLendingPoolContract
  })
}
  1. 修改余额查询逻辑,不依赖即时state
async fetchAccountInfo({daiContract, defaultAccount, ethersIns}){
  let walletBalance=await daiContract.balanceOf(defaultAccount)
  window.alert("stop")
  walletBalance = ethersIns.utils.formatEther(walletBalance, 'ether')
  // 如需打印最新状态,放在setState回调中
  this.setState({walletBalance}, () => {
    console.log('最新状态:', this.state)
  });
}
  1. 清理render方法中的无效注释
    删除JSX中包裹h2标签的//////////和===>>>标记,避免语法解析异常,保留余额渲染标签即可:
<center><img className='Diag' src={bodyImage} alt="blockchain" /></center>
<h2>{this.state.walletBalance}</h2>

额外检查项

  • 确认浏览器钱包已切换到以太坊主网,你代码中写的DAI、cDAI、Aave借贷池地址都是主网地址,切换到其他网络会导致合约调用失败。
  • 发起钱包连接请求时确认用户已授权账户访问,否则defaultAccount为null也会导致查询失败。

内容的提问来源于stack exchange,提问作者Azzor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 20:24:19