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

Wagmi部署至Vercel后无法读写智能合约,本地运行正常

Wagmi部署至Vercel后无法调用合约读写函数的解决方案

问题背景

本地开发环境中,使用Wagmi可正常读写智能合约属性;但部署到Vercel后,仅能连接钱包,调用合约读写函数时触发报错:

Uncaught (in promise) TypeError: y is not a function

报错位置指向SetUsername.jsx的39行和35行,相关业务代码如下:

import React, { useEffect, useState } from 'react'
import  {FaTimes} from 'react-icons/fa'
import { useContractRead, useContractWrite, usePrepareContractWrite, useWaitForTransaction } from 'wagmi'
import { useStateContext } from '../context'

const CreatePoll = () => {
    const {createPoll, setCreatePoll , account, contractAbi, contractAddress, setCandidates } = useStateContext()
    const [name, setName] = useState('')
    const [description, setDescription] = useState('')
    const [image, setImage] = useState('')

    const { config } = usePrepareContractWrite({
        address: contractAddress,
        abi: contractAbi,
        functionName: 'addCandidate',
        args: [name, description, image]
    })
    const {write,data} = useContractWrite(config)

    const { isSuccess } = useWaitForTransaction({
      hash: data?.hash,
    })

    const { refetch: refetchCandidates } = useContractRead({
      address: contractAddress,
      abi: contractAbi,
      functionName: 'getCandidates',
      onSuccess(data) {
        setCandidates(data)
      },
    });

    const handleSubmit = async(e) => {
        e.preventDefault()
        if(account){
            if(!name || !description || !image) return alert('plz fill in the form') 
            await write?.()
            onClose()
        } else{
            alert('Connect to metamask')
        }   
    }
    
    const onClose = ()=> {
        setName('')
        setDescription('')
        setImage('')
        setCreatePoll('scale-0')
    }
    
    useEffect(() => {
        refetchCandidates?.()
    }, [isSuccess]);

  return (
    <div className={`fixed h-screen w-screen top-0 z-50 left-0 flex items-center justify-center
            bg-black bg-opacity-50 transform transition-transform duration-400 ${createPoll}`}
        >
            <div className="bg-white shadow-xl shadow-black rounded-xl w-10/12 md:w-2/5 h-7/12 p-6">
                <form className="flex flex-col" onSubmit={handleSubmit}>
                    <div className="flex flex-row justify-between items-center">
                        <p className="font-bold text-gray-800">Insert Income Details</p>
                        <button
                            type="button"
                            onClick={onClose} 
                            className="border-0 bg-transparent hover:text-md focus:outline-none"
                        >
                            <FaTimes />
                        </button>
                    </div>

                    <div className="flex flex-row items-center justify-center rounded-lg bg-gray-800 mt-5">
                        <input 
                            type="text" 
                            className="block w-full p-2 text-sm text-slate-500 bg-transparent rounded-md border-0 focus:outline-none focuse:ring-0"
                            name="name"
                            placeholder="Name"
                            onChange={(e)=>setName(e.target.value)}
                            value={name}
                            required
                        />
                    </div>

                    <div className="flex flex-row items-center justify-center rounded-lg bg-gray-800 mt-5">
                        <textarea 
                            type="text" 
                            className="block w-full p-2 text-sm text-slate-500 bg-transparent rounded-md border-0 focus:outline-none focuse:ring-0"
                            name="description"
                            placeholder="Description"
                            onChange={(e)=>setDescription(e.target.value)}
                            value={description}
                            required
                        />
                    </div>

                    <div className="flex flex-row items-center justify-center rounded-lg bg-gray-800 mt-5">
                        <input 
                            type="url" 
                            className="block w-full p-2 text-sm text-slate-500 bg-transparent border-0 rounded-md  focus:outline-none focuse:ring-0"
                            name="image"
                            placeholder="Image"
                            onChange={(e)=>setImage(e.target.value)}
                            value={image}
                            required
                        />
                    </div>
                    <div className="flex flex-row items-center justify-center pt-10  rounded-lg">
                        <button className='btn bg-accent px-10 w-1/2 rounded-full' type='submit'> Submit</button>
                    </div>
                </form>
            </div>            
        </div>
  )
}

export default CreatePoll

问题分析

  1. 代码压缩混淆导致变量异常:Vercel默认开启生产环境代码压缩,y是压缩后的变量名,实际对应代码中的write或refetchCandidates函数,因未正确初始化导致调用时触发"不是函数"的错误。
  2. Hook依赖缺失:usePrepareContractWrite未添加状态依赖,当name/description/image变化时,config未重新生成,导致write函数无效。
  3. 环境变量配置问题:Vercel上未正确配置合约地址、ABI等环境变量,导致生产环境下无法正确连接合约。

解决方案

1. 补全Hook依赖项

给usePrepareContractWrite添加依赖数组,确保状态更新时重新生成合约调用配置:

const { config } = usePrepareContractWrite({
    address: contractAddress,
    abi: contractAbi,
    functionName: 'addCandidate',
    args: [name, description, image],
}, [name, description, image, contractAddress, contractAbi]) // 添加依赖

2. 安全调用合约函数

在handleSubmit中增强write函数的存在性检查,避免调用undefined:

const handleSubmit = async(e) => {
    e.preventDefault()
    if(account){
        if(!name || !description || !image) return alert('plz fill in the form') 
        // 替换原write?.()调用
        if (write) {
            await write()
        } else {
            alert('合约调用准备未完成,请重试')
        }
        onClose()
    } else{
        alert('Connect to metamask')
    }   
}

3. 修正useEffect依赖

给useEffect添加refetchCandidates依赖,确保函数引用变化时能正确触发:

useEffect(() => {
    refetchCandidates?.()
}, [isSuccess, refetchCandidates]) // 添加refetchCandidates到依赖

4. 检查Vercel环境变量

登录Vercel控制台,进入项目的"Settings"->"Environment Variables",确认contractAddress、contractAbi等变量已正确配置,且和本地开发环境一致。

5. 临时关闭代码压缩(排查用)

如果怀疑是压缩导致的问题,可在项目配置文件中关闭压缩(以Next.js为例,修改next.config.js):

module.exports = {
    compress: false,
}

排查完成后建议重新开启压缩,避免影响性能。

内容的提问来源于stack exchange,提问作者Anees K.A

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 05:52:13