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

React Native+Firebase实时数据库双人Bingo游戏异步问题及等待页求助

问题解决与实现方案

一、setGame 返回 undefined 的原因及修复

核心问题

原 setGame 函数未返回 Promise,导致使用 await 时无法获取有效结果。同时函数内部存在异步操作未正确等待、遍历逻辑无法中断等问题。

修复后的代码

1. 重构 create 函数(返回游戏密钥)

export function create(game) {
  const db = getDatabase();
  const newGameKey = push(child(ref(db), 'GAME')).key;
  return set(ref(db, '/GAME/' + newGameKey), game)
    .then(() => {
      console.log('Game Create!');
      return newGameKey; // 返回新创建的游戏密钥,用于后续监听
    })
    .catch((error) => {
      console.log(error);
      throw error; // 抛出错误便于上层捕获
    });
}

2. 重构 setGame 函数(返回 Promise 及游戏状态)

export async function setGame(email, game) {
  const dbRef = ref(getDatabase());
  const snapshot = await get(child(dbRef, 'GAME/'));
  
  if (snapshot.exists()) {
    // 使用 for...of 遍历,可随时中断循环找到第一个可用游戏
    for (const childSnapshot of snapshot.children()) {
      const key = childSnapshot.key;
      const { player1, player2 } = childSnapshot.val();
      
      if (player2 === "" && email !== player1) {
        await updateGame(email, key);
        return { type: 'UPDATE', gameKey: key }; // 标记为加入已有游戏
      }
    }
    // 无可用游戏,创建新游戏
    const gameKey = await create(game);
    return { type: 'CREATE', gameKey: gameKey };
  } else {
    // 首次创建游戏
    const gameKey = await create(game);
    return { type: 'CREATE', gameKey: gameKey };
  }
}

3. 确保 updateGame 返回 Promise(已正确实现)

export function updateGame(email, key) {
  console.log('Update: ' + key);
  const db = getDatabase();
  const updates = {};
  updates[`/GAME/${key}/player2`] = email;
  return update(ref(db), updates);
}

二、等待页面实现方案

核心思路

通过状态控制条件渲染,结合 Firebase 实时监听功能,在玩家创建游戏后持续监听房间状态,直到第二名玩家加入。

修复后的 Game 组件

function Game() {
  const authCtx = useContext(AuthContext);
  const gameCtx = useContext(GameContext);
  const [isWaiting, setIsWaiting] = useState(false);
  const [gameKey, setGameKey] = useState(null);
  const [isLoading, setIsLoading] = useState(true); // 新增初始化加载状态

  useEffect(() => {
    let unsubscribe = null;

    async function gamePlay() {
      try {
        // 建议:若 GameContext 使用 useState/reducer,应通过 setter 更新 player1
        gameCtx.player1 = authCtx.token;
        
        const result = await setGame(authCtx.token, gameCtx);
        setGameKey(result.gameKey);
        
        if (result.type === 'CREATE') {
          setIsWaiting(true);
          // 监听游戏房间,等待第二名玩家加入
          const db = getDatabase();
          const gameRef = ref(db, `/GAME/${result.gameKey}`);
          unsubscribe = onValue(gameRef, (snapshot) => {
            const gameData = snapshot.val();
            if (gameData.player2 && gameData.player2 !== "") {
              setIsWaiting(false);
              gameCtx.player2 = gameData.player2; // 更新上下文的第二名玩家信息
            }
          });
        } else if (result.type === 'UPDATE') {
          setIsWaiting(false);
          // 获取已有游戏的玩家1信息
          const db = getDatabase();
          const gameRef = ref(db, `/GAME/${result.gameKey}`);
          const snapshot = await get(gameRef);
          gameCtx.player1 = snapshot.val().player1;
        }
      } catch (error) {
        console.error('游戏初始化失败:', error);
        // 可添加错误提示逻辑
      } finally {
        setIsLoading(false);
      }
    }

    gamePlay();

    // 组件卸载时清理监听
    return () => {
      if (unsubscribe) unsubscribe();
    };
  }, []);

  // 初始化加载状态
  if (isLoading) {
    return <LoadingOverlay message="Initializing game..." />;
  }

  // 等待第二名玩家状态
  if (isWaiting) {
    return <LoadingOverlay message="Waiting for another player... " />;
  }

  // 游戏开始,渲染卡片
  return <Card gameKey={gameKey} />;
}

export default Game;

关键改进点

  1. 条件渲染:通过 isWaiting 状态控制等待页面与游戏卡片的切换,避免在 useEffect 中返回 JSX 的错误做法。
  2. 实时监听:创建游戏后,通过 Firebase 的 onValue 监听房间状态,一旦检测到第二名玩家加入,自动切换到游戏界面。
  3. 内存泄漏防护:在组件卸载时清理 Firebase 监听,避免内存泄漏。
  4. 错误处理:添加 try/catch 捕获初始化过程中的错误,提升稳定性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 18:50:25