React中useEffect首次触发后setState无法再次生效的问题
React函数组件中调用合约后状态不更新的解决方法
问题根源
- 闭包陷阱:
callSmartContract里直接访问的approvalsList是组件初始渲染时被闭包捕获的旧状态,合约调用成功后过滤的是旧数组,导致状态更新无法反映最新数据。 - useEffect无依赖数组:你的
useEffect没设置依赖项,会在组件每次渲染时都触发API请求,不仅浪费资源,还可能干扰状态更新逻辑。 - 冗余状态管理:
noApprovals可以直接通过approvalsList.length判断,不需要单独维护状态,减少出错概率。
修复方案
1. 用函数式更新修改状态
React的setState支持传入函数,函数会接收当前最新的状态值,彻底避开闭包问题:
setApprovalsList(prevList => prevList.filter(e => e !== address));
2. 给useEffect添加依赖数组
把publicAddress作为依赖项,确保只有当地址变化时才重新请求数据,避免无限循环:
useEffect(()=>{ axios.get("http://localhost:3001/get-user",{ params:{ address: publicAddress } }).then((response) => { const jsonArray = JSON.parse(response.data.approved_users); setApprovalsList(jsonArray); }) }, [publicAddress]); // 添加依赖数组
3. 移除冗余的noApprovals状态
直接在渲染时判断approvalsList.length === 0,不用单独维护状态:
{approvalsList.length === 0 && <center style={{paddingTop:"150px"}}> <h2>You have no users to approve</h2> </center> }
完整修复后的代码
function Approvals(){ const [approvalsList, setApprovalsList] = useState([]); const publicAddress = localStorage.getItem("public_address"); const web3JSON = localStorage.getItem("web3"); const web3 = JSON.parse(web3JSON); useEffect(()=>{ axios.get("http://localhost:3001/get-user",{ params:{ address: publicAddress } }).then((response) => { const jsonArray = JSON.parse(response.data.approved_users); setApprovalsList(jsonArray); }) }, [publicAddress]) const callSmartContract = async (address) => { const currentProvider = detectCurrentProvider(); if (currentProvider) { await currentProvider.request({method: 'eth_requestAccounts'}); const web3 = new Web3(currentProvider); const userAccount = await web3.eth.getAccounts(); const account = userAccount[0].toString(); const UserContract = new web3.eth.Contract(User.value,"0xEeA1fcb8280d3723d0930C5fB8281D93929D4e2f",{ from: account }); await UserContract.methods.giveApproval(account, address).send(); alert("Success"); // 使用函数式更新获取最新状态 setApprovalsList(prevList => prevList.filter(e => e !== address)); } } return( <div> <center style={{paddingTop:"150px"}}> <h2>Please select which doctor you would like to approve.</h2> </center> <center style={{paddingTop:"350px"}}> <Box style={{borderRadius: '16px', backgroundColor: '#6ea6be',width:"700px"}}> <List sx={{width: '700px', maxWidth: '1000px'}}> {approvalsList.map((item)=>{ return <ListItemButton component="a" onClick={()=>callSmartContract(item)}> <ListItemText primary={item} secondary="Accept Approval Request" /> </ListItemButton>; })} </List> </Box> </center> {approvalsList.length === 0 && <center style={{paddingTop:"150px"}}> <h2>You have no users to approve</h2> </center> } </div> ) }
内容的提问来源于stack exchange,提问作者Khandkar Islam
相关产品推荐
相关产品推荐

