Next.js中间件中window未定义,如何监听MetaMask账户变更?
问题原因
Next.js 的 _middleware.ts 是运行在服务器端的中间件,执行环境为 Node.js,不存在浏览器的 window 对象,所以你在这里访问 window.ethereum 必然会报错,这就是你看到提示的核心原因。
正确实现方式
MetaMask 的事件监听必须在浏览器客户端环境中执行,也就是要在客户端组件里处理:
1. 基础实现(客户端组件)
在 Next.js 13+ 中,需要给组件加上 'use client' 指令标记为客户端组件,然后通过 useEffect 在组件挂载后监听事件:
'use client' import { useEffect } from 'react' export default function MetaMaskListener() { useEffect(() => { if (typeof window !== 'undefined' && window.ethereum) { console.log('已检测到 MetaMask') const handleAccountChange = (accounts: string[]) => { console.log('账户已变更:', accounts[0]) // 这里添加你的业务逻辑,比如更新用户状态、触发页面跳转等 } // 监听账户变更事件 window.ethereum.on('accountsChanged', handleAccountChange) // 组件卸载时移除监听,避免内存泄漏 return () => { window.ethereum.removeListener('accountsChanged', handleAccountChange) } } else { console.log('未检测到 MetaMask') } }, []) return null // 该组件仅处理监听逻辑,无需渲染UI }
你可以将这个组件导入到根布局或需要监听账户变化的页面中使用。
2. 封装为自定义 Hook(提升复用性)
如果多个组件需要监听账户变化,可以封装成自定义 Hook:
'use client' import { useEffect } from 'react' export function useMetaMaskAccountChange(onChange: (accounts: string[]) => void) { useEffect(() => { if (typeof window !== 'undefined' && window.ethereum) { window.ethereum.on('accountsChanged', onChange) return () => { window.ethereum.removeListener('accountsChanged', onChange) } } }, [onChange]) }
使用示例:
'use client' import { useMetaMaskAccountChange } from '@/hooks/useMetaMaskAccountChange' export default function ProfilePage() { useMetaMaskAccountChange((accounts) => { console.log('账户更新:', accounts[0]) // 执行业务逻辑,比如重新拉取用户数据 }) return <div>用户页面</div> }
3. 用 Wagmi 库简化操作(推荐)
如果你的项目涉及大量 Web3 操作,推荐使用 Wagmi 库,它已封装了 MetaMask 的事件监听、账户连接等常用功能:
'use client' import { useAccount } from 'wagmi' export default function AccountInfo() { const { address, isConnected } = useAccount() // useAccount 会自动监听账户变更,账户变化时组件自动重渲染 useEffect(() => { if (isConnected) { console.log('当前账户:', address) } }, [address, isConnected]) return ( <div> {isConnected ? `当前账户: ${address}` : '未连接钱包'} </div> ) }
内容的提问来源于stack exchange,提问作者Mohanraj G
相关产品推荐
相关产品推荐

