React中Ether.js+ABI调用合约无响应问题排查与解决
问题:调用NFT合约view方法无响应且无日志输出
我已将智能合约部署至以太坊主网,编写了导出合约调用函数的JavaScript文件,在React组件Gallery中设置按钮,点击后调用getOwnerOfToken方法,但无任何反应也无日志输出。已知这是只读view方法,仅需Metamask作为provider,且已通过window.ethereum验证Metamask已加载。
相关代码
Gallery.js(React组件)
import React from "react"; import { getOwnerOfToken } from "../services/nftcontract"; class Gallery extends React.Component { constructor(props){ // constructor代码略 } // 由React按钮的onClick调用 handleProfileChange = (selectedIndex) => { getOwnerOfToken(selectedIndex).then((address) => { this.setState({ currentSelectionnOwner: address }); console.log(this.state.currentSelectionnOwner); }); } render() { // 绑定了回调函数的按钮 return <button onClick={() => this.handleProfileChange()}>Change Profile</button> } }
services/nftcontract.js
import { ethers } from "ethers"; // 注:完整ABI来自Etherscan的ABI板块,此处为示例简化版 const abi = [ { inputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], name: "ownerOf", outputs: [{ internalType: "address", name: "", type: "address" }], stateMutability: "view", type: "function", }, ]; const provider = new ethers.providers.Web3Provider(window.ethereum); const address = global.config.addresses.collections.genesis; const contract = new ethers.Contract(address, abi, provider); const getOwnerOfToken = async (tokenid) => { return await contract.ownerOf(tokenid); }; export { getOwnerOfToken };
问题解决说明
问题根源是Metamask注入时机问题:应用启动时,provider和contract的初始化代码可能在Metamask完成window.ethereum注入前执行,首次访问应用时极易触发该问题。
解决方法是将provider、contract等变量的创建移至异步函数内部,每次发起调用时动态创建合约实例:
const getOwnerOfToken = async (tokenid) => { const provider = new ethers.providers.Web3Provider(window.ethereum); const address = global.config.addresses.collections.genesis; const contract = new ethers.Contract(address, abi, provider); const ownerAddress = await contract.ownerOf(tokenid); // console.log(`EFService: ${ownerAddress}`); return ownerAddress; };
内容的提问来源于stack exchange,提问作者Potion
相关产品推荐
相关产品推荐

