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

如何将getRoomInfo中docSnap.data()的值存入变量?useState触发无限循环

解决React中Firestore房间数据存储与渲染问题

问题核心

你遇到的无限循环是因为直接在组件渲染流程中调用状态更新函数,导致组件反复重渲染;普通变量会在组件重渲染时被重置,所以JSX无法持续访问到数据。下面是具体的修复方案:

步骤1:新增状态存储房间详情

添加一个roomDetails状态来保存每个房间的完整信息,用对象存储(键为房间ID,值为房间数据)方便后续在JSX中快速查找:

const [roomDetails, setRoomDetails] = useState({});

步骤2:用useEffect控制数据获取时机

使用useEffect限定数据获取的触发条件,避免无限循环:

  • 第一个useEffect:当currentUser变化时(用户登录/登出),调用getListOfRooms获取用户加入的房间列表。
  • 第二个useEffect:当listOfRooms更新时,批量获取每个房间的详情并更新状态。

步骤3:改造异步数据获取逻辑

修改getRoomInfo和getRoomInfoHelper,用Promise.all批量处理异步请求,避免多次触发状态更新:

const getRoomInfo = async (roomId) => {
  const docRef = doc(db, "Rooms", roomId);
  const docSnap = await getDoc(docRef);
  return docSnap.exists() ? { id: roomId, ...docSnap.data() } : null;
};

const getRoomInfoHelper = async () => {
  if (listOfRooms.length === 0) return;
  
  // 批量获取所有房间详情
  const roomDataPromises = listOfRooms.map(s => getRoomInfo(s.id));
  const roomDataList = await Promise.all(roomDataPromises);
  
  // 过滤掉无效数据,转成对象格式
  const newRoomDetails = roomDataList.reduce((acc, room) => {
    if (room) acc[room.id] = room;
    return acc;
  }, {});
  
  setRoomDetails(newRoomDetails);
};

完整修改后的代码

import { React, useEffect, useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import "../index.css";
import "bootstrap/dist/css/bootstrap.css";
import Navbar1 from "./NavBar1";
import { db } from "../firebase";
import { auth } from "../firebase";
import { useAuthValue } from "../context.js";
import { onAuthStateChanged } from "firebase/auth";
import {
  collection,
  getDocs,
  doc,
  updateDoc,
  arrayUnion,
  getDoc,
} from "firebase/firestore";

const JoinedRooms = () => {
  const { currentUser } = useAuthValue();
  const [listOfRooms, setListOfRooms] = useState([]);
  const [roomDetails, setRoomDetails] = useState({}); // 新增状态存储房间详情

  useEffect(() => {
    if (!currentUser) return; // 用户未登录时不执行
    const getListOfRooms = async () => {
      const docRef = doc(db, "Users", currentUser.uid);
      const docSnap = await getDoc(docRef);

      if (docSnap.exists()) {
        setListOfRooms(docSnap.data().Chatrooms);
      } else {
        console.log("No such document!");
      }
    };
    getListOfRooms();
  }, [currentUser]); // 依赖currentUser,用户状态变化时重新获取

  useEffect(() => {
    const getRoomInfo = async (roomId) => {
      const docRef = doc(db, "Rooms", roomId);
      const docSnap = await getDoc(docRef);
      return docSnap.exists() ? { id: roomId, ...docSnap.data() } : null;
    };

    const getRoomInfoHelper = async () => {
      if (listOfRooms.length === 0) return;
      
      const roomDataPromises = listOfRooms.map(s => getRoomInfo(s.id));
      const roomDataList = await Promise.all(roomDataPromises);
      
      const newRoomDetails = roomDataList.reduce((acc, room) => {
        if (room) acc[room.id] = room;
        return acc;
      }, {});
      
      setRoomDetails(newRoomDetails);
    };

    getRoomInfoHelper();
  }, [listOfRooms]); // 依赖listOfRooms,列表更新时重新获取房间详情

  // 在JSX中可以这样访问房间数据
  return (
    <div>
      <Navbar1 />
      <div className="container mt-4">
        <h2>我加入的房间</h2>
        <div className="row">
          {listOfRooms.map(room => {
            const detail = roomDetails[room.id];
            if (!detail) return <div key={room.id}>加载中...</div>;
            return (
              <div key={room.id} className="col-md-4 mb-3">
                <div className="card">
                  <div className="card-body">
                    <h5 className="card-title">{detail.name}</h5>
                    <p className="card-text">{detail.description}</p>
                    {/* 其他房间信息 */}
                  </div>
                </div>
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
};

export default JoinedRooms;

关键说明

  • 避免无限循环:所有数据获取逻辑都放在useEffect中,通过依赖数组控制触发时机,只有当依赖项变化时才执行。
  • 异步批量处理:用Promise.all同时发起多个Firestore请求,提升效率,并且一次性更新状态,减少组件重渲染次数。
  • JSX访问数据:通过roomDetails[room.id]可以直接拿到对应房间的详情,同时处理加载状态,避免渲染空数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 15:38:18