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

Next.js中使用useEffect获取Firebase数据报Invalid hook call错误如何修复

错误修复方案

你触发的Error: Invalid hook call. Hooks can only be called inside of the body of a function component错误,核心原因是违反了React Hook的调用规则:所有Hook必须在React函数组件的最顶层作用域调用,禁止在嵌套函数、循环、条件判断、useEffect回调内部调用。
你的代码问题出在第二个useEffect内部的map循环里调用了useCollection这个Hook,不符合调用规范。

修复方案

方案1:替换嵌套的useCollection为Firebase原生查询

不需要在循环内使用Hook,直接用Firebase SDK的get()方法异步拉取数据,修改后代码如下:

// 顶层Hook保留,符合调用规范
useEffect(()=>{
  console.log("session",session)
},[session]);

const [myChats] = useCollection(db.collection('chats').where('users','array-contains',session.user.email));

useEffect(()=>{
  // 先清空旧数据,避免重复追加
  setChats([])
  setMyChat([])
  // 遍历执行副作用用forEach语义更清晰
  myChats?.docs?.forEach(async (user) => {
    const chatId = user.id
    setMyChat((prevState) => [...prevState, chatId])
    // 直接用原生get方法查询,不需要Hook
    const chatSnapshot = await db
      .collection('chats')
      .doc(chatId)
      .collection('messeges')
      .orderBy('timestamp','asc')
      .limitToLast(1)
      .get()
    // 处理查询结果
    if(!chatSnapshot.empty) {
      const chat = chatSnapshot.docs[0]
      console.log("chat",chat.id)
      setChats((prev) => [...prev, chat])
    }
  })
},[myChats])

console.log("myChat",chats)

方案2:拆分独立子组件使用useCollection

如果你需要用到useCollection的实时响应更新能力,可以把单条聊天的消息获取逻辑拆为独立子组件,在子组件顶层调用Hook:

  1. 定义子组件
function ChatItem({ chatId, onChatLoad }) {
  // 子组件顶层调用Hook,符合规范
  const [chatSnapshot] = useCollection(
    db.collection('chats').doc(chatId).collection('messeges').orderBy('timestamp','asc').limitToLast(1)
  )
  useEffect(() => {
    if(chatSnapshot?.docs[0]) {
      const chat = chatSnapshot.docs[0]
      console.log("chat", chat.id)
      onChatLoad(chat)
    }
  }, [chatSnapshot, onChatLoad])
  return <div>{/* 可直接渲染单条聊天内容 */}</div>
}
  1. 父组件逻辑调整
useEffect(()=>{
  console.log("session",session)
},[session]);

const [myChats] = useCollection(db.collection('chats').where('users','array-contains',session.user.email));

useEffect(()=>{
  if(myChats?.docs) {
    setMyChat(myChats.docs.map(user => user.id))
  }
},[myChats])

// 渲染时遍历生成子组件即可
// return <div>{myChat.map(id => <ChatItem key={id} chatId={id} onChatLoad={(chat) => setChats(prev => [...prev, chat])} />)}</div>

额外注意事项

  • 你的代码里消息集合拼写为messeges,确认是否是手误,正确拼写应为messages,拼写错误会导致查询不到数据
  • 每次myChats更新时先清空旧的聊天列表,避免重复渲染重复数据

内容的提问来源于stack exchange,提问作者Jeevan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 18:24:10