React集成Web3调用mintToken报.then不是函数错误
问题描述
在集成ERC721智能合约与React前端时,调用合约方法触发运行时报错,此前因react-scripts版本问题降级到v5以下版本后出现该错误,怀疑两者存在关联。
控制台报错信息:
Uncaught TypeError: _Web3Client__WEBPACK_IMPORTED_MODULE_1__.mintToken.then is not a function
报错截图:
问题根因
该报错和react-scripts版本降级无任何关联,全部为代码逻辑错误导致,共3处问题:
- 核心报错原因:App.js中未执行
mintToken函数,直接对导入的函数对象本身调用.then()方法。async函数只有被执行后才会返回Promise实例,直接引用函数对象不存在then方法,因此触发类型错误。 - 合约调用参数不匹配:Solidity合约中定义的
mint()方法无入参,铸币目标地址默认取交易发起者msg.sender,但前端调用时错误传入了selectedAccount作为参数,会导致合约调用失败。 - 初始化逻辑隐患:Web3初始化逻辑中未等待用户完成钱包授权就继续执行后续代码,可能出现
selectedAccount为空、合约实例初始化异常的问题;同时Web3实例化时遗漏new关键字,不符合官方初始化规范。
修复方案
1. 修正App.js逻辑
首先在组件加载时提前初始化Web3连接,其次调用mintToken时添加括号执行函数,拿到Promise实例后再处理回调:
import React, { useEffect, useState } from 'react'; import { init, mintToken } from './Web3Client'; function App() { const [minted, setMinted] = useState(false); // 组件挂载时提前初始化Web3连接 useEffect(() => { init().catch(err => console.log('Web3初始化失败:', err)); }, []); const mint = () => { // 加()执行mintToken函数,拿到返回的Promise mintToken() .then((tx) => { console.log('铸币交易成功:', tx); setMinted(true); }) .catch((err) => { console.log('铸币失败:', err); }); }; return ( <div className="App"> {!minted ? ( <button onClick={() => mint()}>Mint Token</button> ) : ( <p>Token Minted successfully</p> )} </div> ); } export default App;
2. 修正Web3Client.js逻辑
给钱包授权请求加await保证执行顺序,补全Web3实例化的new关键字,移除合约mint方法调用时多余的参数:
import Web3 from 'web3'; import NFTContract from './NFT.json'; let selectedAccount; let nftContract; let isInitialized = false; export const init = async () => { let provider = window.ethereum; if (typeof provider !== 'undefined') { // 等待用户完成钱包授权,再获取地址 const accounts = await provider .request({ method: 'eth_requestAccounts' }) .catch((err) => { console.log('钱包授权失败:', err); return; }); selectedAccount = accounts[0]; console.log(`selected account is ${selectedAccount}`); window.ethereum.on('accountsChanged', function (accounts) { selectedAccount = accounts[0]; console.log(`Selected account changed to ${selectedAccount}`); }); } // 补全new关键字初始化Web3实例 const web3 = new Web3(provider); const networkId = await web3.eth.net.getId(); nftContract = new web3.eth.Contract( NFTContract.abi, NFTContract.networks[networkId].address ); isInitialized = true; }; export const mintToken = async () => { if (!isInitialized) { await init(); } // 合约mint方法无入参,移除多余的地址传参 return nftContract.methods .mint() .send({ from: selectedAccount }); };
3. 注意事项
- 确保MetaMask当前选中的网络和NFT合约部署的网络一致,否则会读取不到合约部署地址触发新的报错。
- 确保已在前端项目目录下正确导入部署后生成的
NFT.json合约ABI文件,且文件内包含对应网络的合约地址配置。
内容的提问来源于stack exchange,提问作者Zoha Akram
相关产品推荐
相关产品推荐

