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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 17:25:53