如何基于WalletConnect Web3Modal编写登录Hook处理钱包鉴权
解决方案
你的核心问题是open()在弹窗打开时就resolve,没法等到钱包实际连接成功。其实可以利用wagmi的useAccount状态的实时更新特性,配合useEffect监听连接状态,当钱包真正连接成功后再触发服务器请求。
修改后的useLogin Hook
import { useAccount, useSigner } from "wagmi"; import signMessage from "@/modules/auth/services/signMessage"; import type { Signer } from "@wagmi/core"; import { useWeb3Modal } from "@web3modal/react"; import { useEffect, useState } from "react"; const useLogin = () => { const { isConnected, address } = useAccount(); const { open } = useWeb3Modal(); const { data: signer } = useSigner(); const [hasInitiatedAuth, setHasInitiatedAuth] = useState(false); // 监听钱包连接状态,连接成功且未发起过鉴权时触发请求 useEffect(() => { if (isConnected && address && signer && !hasInitiatedAuth) { signMessage(address, signer) .then((accessToken) => { console.log(accessToken); // 这里可处理拿到token后的逻辑,比如存localStorage、更新全局状态等 setHasInitiatedAuth(true); // 标记已完成鉴权,避免重复请求 }) .catch((err) => { console.error("鉴权请求失败:", err); setHasInitiatedAuth(false); // 失败后允许重试 }); } }, [isConnected, address, signer, hasInitiatedAuth]); // 点击按钮仅负责打开钱包弹窗 const handleLoginClick = () => { if (!isConnected) { open(); } }; return handleLoginClick; }; export default useLogin;
使用方式调整
import { Button } from "@mui/material"; import useLogin from "../hooks/useLogin"; const Home = (props) => { const login = useLogin(); return ( <> <Button variant="contained" onClick={login} disableElevation>Connect wallet</Button> </> ); };
关键说明
- 状态监听:通过
useEffect监听isConnected、address、signer三个状态,只有三者都有效(钱包连接成功、地址存在、签名器可用)时,才触发服务器鉴权请求。 - 重复请求控制:用
hasInitiatedAuth标记是否已发起鉴权,避免组件重渲染时重复调用接口;请求失败时重置状态,允许用户重试。 - 职责分离:点击按钮只负责打开钱包选择弹窗,后续连接状态变化由wagmi自动跟踪,无需手动处理
open()的返回值。
内容的提问来源于stack exchange,提问作者FaSh
相关产品推荐
相关产品推荐

