如何解决dapp报错:Cannot read properties of undefined (reading 'getMood')
解决Goerli测试网Dapp调用
getMood时的TypeError问题 问题分析
报错skeleton.html:115 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'getMood')的核心原因是:页面加载后,用户未完成钱包授权(异步流程eth_requestAccounts还未执行完毕)就点击操作按钮,此时MoodContract合约实例还未被赋值,处于undefined状态。
此前问题偶发是因为用户可能在钱包授权完成后才点击按钮,近期必现则是由于用户操作更快,或钱包/网络响应变慢,导致授权流程未完成就触发了合约方法调用。
解决方案
1. 方法调用前增加实例检查
修改getMood和setMood函数,先判断合约实例是否初始化完成,未完成则提示用户等待:
async function getMood(){ if (!MoodContract) { alert("请先完成钱包授权,等待初始化完成后再操作"); return; } var getMoodPromise = MoodContract.getMood(); var mood= await getMoodPromise; console.log(mood); } async function setMood(){ if (!MoodContract) { alert("请先完成钱包授权,等待初始化完成后再操作"); return; } var mood= document.getElementById("mood").value; var setMoodPromise = MoodContract.setMood(mood); await setMoodPromise; }
2. 按钮状态联动初始化流程
先将按钮设为禁用状态,等合约实例初始化完成后再启用,从根源避免误操作:
- 给按钮添加ID并设置禁用属性:
<button id="getMoodBtn" onclick="getMood()" disabled>Get Mood</button> <button id="setMoodBtn" onclick="setMood()" disabled>Set Mood</button>
- 在合约初始化完成后启用按钮,并处理授权失败的情况:
provider.send("eth_requestAccounts", []).then(() => { provider.listAccounts().then(function(accounts) { signer = provider.getSigner(accounts[0]); MoodContract = new ethers.Contract(MoodContractAddress, MoodContractABI, signer); // 启用操作按钮 document.getElementById("getMoodBtn").disabled = false; document.getElementById("setMoodBtn").disabled = false; }); }).catch(err => { console.error("钱包授权失败:", err); alert("钱包授权失败,请重试"); });
3. 优化异步流程写法(可选)
用async/await替代嵌套then,让代码更易读且逻辑更清晰:
async function initContract() { try { await provider.send("eth_requestAccounts", []); const accounts = await provider.listAccounts(); signer = provider.getSigner(accounts[0]); MoodContract = new ethers.Contract(MoodContractAddress, MoodContractABI, signer); // 启用按钮 document.getElementById("getMoodBtn").disabled = false; document.getElementById("setMoodBtn").disabled = false; } catch (err) { console.error("初始化失败:", err); alert("初始化失败,请检查钱包连接或重试"); } } // 页面加载后自动执行初始化 window.onload = initContract;
内容的提问来源于stack exchange,提问作者Coding_templar
相关产品推荐
相关产品推荐

