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

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>
  )
}

问题分析

  1. Uncaught (in promise) No ethereum object found错误:

    • sendTransaction和getEthereumContract函数中直接使用的ethereum变量未在作用域内声明,未正确获取window.ethereum。
    • catch块主动抛出的自定义错误会掩盖原始问题,导致错误提示不准确。
  2. sendTransaction无法获取表单数据:

    • Welcome组件中调用Input组件时未传递value属性,表单输入未与Context中的formData双向绑定,formData始终为初始空值。
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 15:24:08