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

React+Firebase数组仅在代码保存时渲染问题求助

问题修复方案

问题根源

  1. 异步循环处理错误:onSnapshot回调中使用forEach结合async/await,但forEach不支持异步函数的等待机制,导致所有getContactInfo异步请求还未完成,就执行了setLatestsChats(tempLatestChats),此时数组为空或不完整。
  2. 状态更新未被监听:LatestChat组件中第二个useEffect的依赖数组为空,仅在组件挂载时执行一次,不会响应latestsChats的后续更新。
  3. 未清理Firebase订阅:onSnapshot的订阅未被清理,可能导致内存泄漏和重复监听。

修复步骤

1. 修复useChatFunctions中的异步逻辑与订阅清理

将forEach替换为map,通过Promise.all等待所有联系人信息请求完成后再更新状态,同时返回订阅清理函数:

export const useChatFunctions = () => {
  const [messages, setMessages] = useState([]);
  const [chatId, setChatId] = useState("");
  const [loadingMessage, setLoadingMessage] = useState(undefined);
  const [contactName, setContactName] = useState("");
  const [latestsChats, setLatestsChats] = useState([]);

  const fetchLatestChats = (userId) => {
      const q = query(
        collection(db, "chat"),
        where("arrayUsersId", "array-contains", userId)
      );
    
      const unsubscribe = onSnapshot(q, async (querySnapShot) => {
        const tempLatestChats = await Promise.all(
          querySnapShot.docs.map(async (doc) => {
            const chatData = doc.data();
            const otherUserId = chatData.arrayUsersId.find(id => id !== userId);
            const contactInfo = await getContactInfo(otherUserId);
    
            return {
              ...chatData,
              contactInfo,
              otherUserId
            };
          })
        );
        setLatestsChats(tempLatestChats);
      });

      return unsubscribe;
  };
  
  const getContactInfo = async (userId) => {
    const q = query(collection(db, "user"), where("userId", "==", userId));
    const querySnapshot = await getDocs(q);
  
    if (!querySnapshot.empty) {
      const userDoc = querySnapshot.docs[0];
      return userDoc.data();
    } else {
      return { displayName: "Nome do Contato Desconhecido", profilePictureUrl: "" };
    }
  };

  return {
    fetchChat,
    fetchLatestChats,
    sendMessage,
    messages,
    chatId,
    contactName,
    latestsChats,
  };
};

2. 修复LatestChat组件的状态监听

移除多余的latestsChatsList状态,直接使用latestsChats,同时在useEffect中清理Firebase订阅:

import { useEffect } from "react";
import { useChatFunctions } from "../../hooks/useChatFunctions";
import styles from "./LatestChat.module.css";

const LatestChat = ({ userId, setContactId }) => {
  const { fetchLatestChats, latestsChats } = useChatFunctions();

  useEffect(() => {
    const unsubscribe = fetchLatestChats(userId);
    return () => unsubscribe();
  }, [userId, fetchLatestChats]);

  return (
    <ul className={styles.chats_list}>
      {latestsChats.map((chat, i) => (
        <li key={chat.chatId || i} onClick={() => setContactId(chat.otherUserId)}>
          <div className={styles.profilePicture}>
            <img 
              src={chat.contactInfo.profilePictureUrl || "/default-avatar.png"} 
              alt={chat.contactInfo.displayName} 
            />
          </div>
          <div className={styles.messages_info}>
            <p className={styles.contact_name}>
              {chat.contactInfo.displayName}
            </p>
            <p className={styles.last_message}>
              {chat.messages?.[chat.messages.length - 1]?.message || "无消息"}
            </p>
          </div>
        </li>
      ))}
    </ul>
  );
};

export default LatestChat;

额外优化点

  • 优先使用聊天文档的唯一chatId作为列表项key,比索引更稳定。
  • 添加可选链?.和默认值,避免数据未加载时的渲染报错。
  • getContactInfo返回统一格式的对象,避免联系人不存在时的属性访问错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 15:37:33