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

React Hooks中Firebase数据获取、计算与展示异常问题排查

问题:Firebase Storage获取游戏数据后统计结果无法实时展示

我尝试从Firebase Storage中获取多个「game」对象,计算相关统计数据后展示在表格中,现有代码框架如下:

function calculateTeamStatistics(team) {
   // 遍历所有游戏,在文件中查找队伍名称,计算统计数据
}

useEffect(() => {
   async function prepareStatistics() {
    // 遍历所有游戏,识别队伍(没有现成的队伍列表)
    calculateTeamStatistics(team)
   }
   prepareStatistics();
}, []);


useEffect(() => {
    async function getAllGames(tournament: string) {
      let gameFileReferences: any = [];
      let allGames: any[] = [];
      const storageRef = storage.ref();
      let gameRef = storageRef.child(`${tournament}_results/`).listAll();
      await gameRef.then((gameFiles) => {
        gameFileReferences = gameFiles.items;
        gameFileReferences.forEach((game: any) => {
          storageRef
            .child(`${tournament}_results/${game.name}`)
            .getDownloadURL()
            .then((url) => {
              axios
                .get(url, {
                  headers: {
                    Accept: "application/json",
                  },
                })
                .then((response) => {
                  allGames.push(response);
                  if (lastModifiedText === "" && response.headers) {
                    setLastModifiedText(response.headers["last-modified"]);
                  }
                })
                .catch((error) => console.log(error));
            });
        });
      });
      setTournamentGames(allGames);
    }

    getAllGames(tournamentId);
  }, []);

目前只有setLastModifiedText钩子能正常工作,刷新浏览器时会更新render中的文本,但统计计算结果无法展示,除非修改render代码并保存。尝试在setModifiedText所在的.then()调用内执行计算与迭代,会出现更多问题。推测是async或useEffect调用位置有误,但无法定位具体问题,已尝试调整各类async与useEffect调用、重构函数,均未解决问题。


解决方案

1. 修复getAllGames中的异步并行问题

当前代码里forEach遍历文件时,内部的getDownloadURL和axios.get都是异步操作,但没有等待所有操作完成就调用了setTournamentGames(allGames),导致allGames为空或不完整,后续统计自然拿不到完整数据。

修改getAllGames,用Promise.all等待所有异步请求完成:

useEffect(() => {
  async function getAllGames(tournament: string) {
    const storageRef = storage.ref();
    const gameFiles = await storageRef.child(`${tournament}_results/`).listAll();
    
    // 用Promise.all批量处理所有异步请求
    const allGamesPromises = gameFiles.items.map(async (game: any) => {
      const url = await storageRef.child(`${tournament}_results/${game.name}`).getDownloadURL();
      const response = await axios.get(url, { headers: { Accept: "application/json" } });
      
      // 仅在lastModifiedText为空时设置
      if (!lastModifiedText && response.headers) {
        setLastModifiedText(response.headers["last-modified"]);
      }
      
      return response;
    });
    
    const allGames = await Promise.all(allGamesPromises);
    setTournamentGames(allGames);
  }

  getAllGames(tournamentId);
}, [tournamentId, lastModifiedText]); // 添加必要依赖项

2. 让统计计算依赖tournamentGames的更新

原prepareStatistics所在的useEffect依赖为空数组,只会执行一次,但此时tournamentGames还未加载完成。需要把tournamentGames作为依赖,确保数据加载完成后再计算统计:

// 假设用状态存储统计结果
const [teamStatistics, setTeamStatistics] = useState({});

useEffect(() => {
  // 游戏数据为空时直接返回
  if (!tournamentGames.length) return;
  
  async function prepareStatistics() {
    // 从游戏数据中提取所有队伍
    const teams = new Set();
    tournamentGames.forEach(game => {
      // 根据实际game数据结构提取队伍,示例为game.data.team1/team2
      teams.add(game.data.team1);
      teams.add(game.data.team2);
    });
    
    // 计算每个队伍的统计数据
    const stats = {};
    teams.forEach(team => {
      stats[team] = calculateTeamStatistics(team, tournamentGames);
    });
    
    setTeamStatistics(stats);
  }
  
  prepareStatistics();
}, [tournamentGames]); // 依赖游戏数据,数据更新时重新计算

3. 调整calculateTeamStatistics函数

让它接收完整的游戏数组,避免内部遍历未加载完成的数据:

function calculateTeamStatistics(team, allGames) {
  let wins = 0;
  let losses = 0;
  // 可添加其他统计字段,比如得分、净胜分等
  
  allGames.forEach(game => {
    const gameData = game.data;
    // 根据实际游戏数据结构判断胜负
    if (gameData.winner === team) {
      wins++;
    } else if (gameData.loser === team) {
      losses++;
    }
  });
  
  return { wins, losses, totalGames: wins + losses };
}

4. 检查依赖项完整性

确保所有用到的状态、props都加入到useEffect的依赖数组中,避免陈旧闭包问题,比如setTournamentGames、setTeamStatistics等(如果使用ESLint,会自动提示缺失的依赖)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 11:01:58