React Web3 NFT铸造报process未定义、钱包需双击连接问题
NFT铸造网站两个问题的原因及修复方案
问题1:连接钱包需要连续点击两次才能获取到钱包地址
产生原因
React 函数组件的setState是异步批处理机制:调用setWalletAddress、setContract时不会立刻修改当前函数闭包里的变量值,只会把更新任务加入队列,等当前同步代码执行完、组件重渲染后,新的state值才会生效。
你在调用set方法后立刻打印walletAddress和contract,拿到的永远是更新前的初始空值,第一次点击只是触发了state更新,等第二次点击触发函数执行时,闭包已经拿到了上一轮更新后的state,才会显示正确值,本质是代码写法问题,不是钱包连接功能真的需要触发两次。
修复代码
把connectWallet里的实例存在临时变量里使用,不要在当前上下文依赖刚set的state:
const connectWallet = async () => { if (typeof window.ethereum !== 'undefined') { const web3 = new Web3(window.ethereum); const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' }); // 先把值存在临时变量 const currentAddress = accounts[0]; const contractInstance = new web3.eth.Contract(ABI, ADDRESS); // 再更新state setWalletAddress(currentAddress); setContract(contractInstance); // 用临时变量打印/后续操作,不要直接读state console.log(currentAddress) console.log(contractInstance) } };
你的路由传props写法没有问题,state更新后组件重渲染会自动把最新的walletAddress和contract传给MintNow组件,不需要额外修改路由配置。
问题2:渲染MintNow页面抛出Uncaught ReferenceError: process is not defined错误
产生原因
这个是构建环境兼容问题,和你的业务逻辑无关:
你用的web3.js依赖部分Node.js原生全局对象,其中process是Node环境专属的变量,浏览器环境本身不存在。Vite、React 18+ 配套的webpack5默认不再自动注入Node.js模块的polyfill(兼容补丁),代码运行到调用process的位置就会抛出这个错误。
修复方案
根据你用的构建工具选对应方案:
- 如果是Vite搭建的项目:
- 安装polyfill插件:
npm install vite-plugin-node-polyfills -D- 在项目根目录的
vite.config.js里启用插件:
import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import { nodePolyfills } from 'vite-plugin-node-polyfills' export default defineConfig({ plugins: [ react(), nodePolyfills() ] }) - 如果是新版create-react-app(webpack5)搭建的项目:
在src/index.js最顶部手动加全局兜底定义即可:window.process = { env: { NODE_ENV: 'production' } }
额外优化建议
MintNow组件里的mint函数没有做初始化校验,用户没连钱包直接进入页面点Mint按钮会报contract不存在的错误,加个前置判断即可:
const MintNow = ({ walletAddress, contract }) => { const mint = async () => { if (!window.ethereum) return alert('请先安装MetaMask等钱包插件') if (!walletAddress || !contract) return alert('请先连接钱包后再铸造') const _mintAmount = Number(document.querySelector("[name=amount]").value); const mintRate = Number(await contract.methods.cost().call()); const totalAmount = mintRate * _mintAmount; contract.methods.mint(walletAddress, _mintAmount).send({ from: walletAddress, value: String(totalAmount) }) } return ( <> <input type='number' name='amount' defaultValue='1' min='1' max='100' /> <button onClick={mint}>Mint</button> </> ); } export default MintNow;
内容的提问来源于stack exchange,提问作者breking bed
相关产品推荐
相关产品推荐

