Web3项目React Context调用sendTransaction报错:ethereum对象未找到
Web3项目Context API表单提交错误修复
问题描述
开发Web3项目时采用Context API实现功能,提交表单数据至Context时遇到两类错误:
TypeError: Cannot read properties of undefined (reading 'map'),定位在TransactionContext.jsx的sendTransaction函数第87行第13位- 调用handleSubmit中的sendTransaction()时,抛出
Uncaught (in promise) No ethereum object found错误
同时sendTransaction方法无法获取表单数据,相关代码如下:
Welcome.jsx代码
const Input = ({ placeholder, name, type, value, handleChange }) => ( <input placeholder={placeholder} type={type} step="0.0001" value={value} onChange={(e) => handleChange(e, name)} /> ) const Welcome = () => { const { currentAccount, connectWallet, handleChange, sendTransaction, formData } = useContext(TransactionContext); const handleSubmit = (e) => { const { addressTo, amount, keyword, message } = formData; e.preventDefault(); if (!addressTo || !amount || !keyword || !message) return; sendTransaction(); }; return ( <div> <Input placeholder="Address To" name="addressTo" type="text" handleChange={handleChange} /> <Input placeholder="Amount (ETH)" name="amount" type="number" handleChange={handleChange} /> <Input placeholder="Keyword (Gif)" name="keyword" type="text" handleChange={handleChange} /> <Input placeholder="Enter Message" name="message" type="text" handleChange={handleChange} /> <div /> {false? <Loader /> : ( <button type="button" onClick={handleSubmit} > Send now </button> )} </div> ) } export default Welcome;
TransactionContext.jsx代码
const getEthereumContract = () => { const provider = new ethers.providers.Web3Provider(ethereum) const signer = provider.getSigner(); const TransactionContract = new ethers.Contract(contractAddress, contractABI, signer) console.log({ provider, signer, TransactionContract }) } export const TransactionProvider = ({ children }) => { const [currentAccount, setCurrentAccount] = useState("") const [formData, setformData] = useState({ addressTo: "", amount: "", keyword: "", message: "" }); const handleChange = (e, name) => { setformData((prevState) => ({ ...prevState, [name]: e.target.value })); }; const sendTransaction = async () => { try { if (!ethereum) return alert("Please install metamask") const { addressTo, amount, keyword, message } = formData; getEthereumContract() } catch (error) { console.log(error) throw new Error("No ethereum object"); } } return ( <TransactionContext.Provider value={{ connectWallet, currentAccount, sendTransaction, handleChange, formData, }}> {children} </TransactionContext.Provider> ) }
问题分析
Uncaught (in promise) No ethereum object found错误:sendTransaction和getEthereumContract函数中直接使用的ethereum变量未在作用域内声明,未正确获取window.ethereum。- catch块主动抛出的自定义错误会掩盖原始问题,导致错误提示不准确。
sendTransaction无法获取表单数据:
- Welcome组件中调用Input组件时未传递
value属性,表单输入未与Context中的formData双向绑定,formData始终为初始空值。
- Welcome组件中调用Input组件时未传递
TypeError: Cannot read properties of undefined (reading 'map')错误:- 推测
contractABI未正确导入或格式错误,初始化合约时解析ABI过程中触发了map调用,而ABI变量为undefined。
- 推测
修复方案
1. 修复ethereum变量未定义及错误处理
修改TransactionContext.jsx中的getEthereumContract和sendTransaction函数,确保正确获取window.ethereum并优化错误逻辑:
// 确保已导入contractABI和contractAddress import contractABI from "./TransactionContract.abi.json"; const contractAddress = "你的合约部署地址"; const getEthereumContract = () => { const ethereum = window.ethereum; if (!ethereum) throw new Error("Ethereum object not found, please install MetaMask"); const provider = new ethers.providers.Web3Provider(ethereum); const signer = provider.getSigner(); const TransactionContract = new ethers.Contract(contractAddress, contractABI, signer); console.log({ provider, signer, TransactionContract }); return TransactionContract; // 返回合约实例供后续调用 } const sendTransaction = async () => { try { const ethereum = window.ethereum; if (!ethereum) { alert("Please install MetaMask to continue"); return; } const { addressTo, amount, keyword, message } = formData; // 二次校验表单数据 if (!addressTo || !amount || !keyword || !message) { alert("Please fill all required fields"); return; } const contract = getEthereumContract(); // 调用合约转账方法(需根据你的合约方法名调整) const tx = await contract.sendTransaction( addressTo, ethers.utils.parseEther(amount), // 转换ETH为wei keyword, message ); await tx.wait(); // 等待交易上链 console.log("Transaction successful:", tx.hash); } catch (error) { console.error("Transaction failed:", error); throw error; // 抛出原始错误便于排查 } }
2. 修复表单数据绑定
在Welcome.jsx中为Input组件添加value属性,实现双向绑定:
// 修改Welcome组件内的Input调用 <div> <Input placeholder="Address To" name="addressTo" type="text" handleChange={handleChange} value={formData.addressTo} /> <Input placeholder="Amount (ETH)" name="amount" type="number" handleChange={handleChange} value={formData.amount} /> <Input placeholder="Keyword (Gif)" name="keyword" type="text" handleChange={handleChange} value={formData.keyword} /> <Input placeholder="Enter Message" name="message" type="text" handleChange={handleChange} value={formData.message} /> {/* 其余代码不变 */} </div>
3. 修复map相关错误
确保contractABI是合法的JSON数组格式,且已正确导入到TransactionContext.jsx中。如果ABI是从Remix或Hardhat导出的,直接导入即可,避免手动修改导致格式错误。
内容的提问来源于stack exchange,提问作者Sohaib Ashraf
相关产品推荐
相关产品推荐

