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

React游戏项目如何优化组件条件渲染的实现逻辑

React游戏条件渲染优化方案

现有写法的问题

你目前用多&&串联判断的写法虽然逻辑直观,但随着游戏状态变多很容易出现判断漏写、重复校验的问题,后续加新状态的时候维护成本很高,而且JSX里堆大量判断逻辑可读性也差。

适配现有代码的优化方案

方案1:状态优先级映射渲染(改动最小,最适配现有逻辑)

你的游戏状态其实是互斥的有限状态:选择游戏 → 创建游戏(随机/自定义) → 游戏中 → 游戏胜利,完全可以提前计算出当前要渲染的组件,不用在JSX里逐个判断:

const App = () => {
  // 原有状态和方法全部保留,不用改
  const [startPlayer, setStartPlayer] = useState("");
  const [endPlayer, setEndPlayer] = useState("");
  const [gameSelected, setGameSelected] = useState(false);
  const [gameStarted, setGameStarted] = useState(false);
  const [gameWon, setGameWon] = useState(false);
  const [winningTeam, setWinningTeam] = useState([]);
  const [gameSolved, setGameSolved] = useState(false);
  const isMobile = useMobileCheck();  

  const resetGame = () => {
    setStartPlayer("");
    setEndPlayer("");
    setGameSelected(false);
    setGameStarted(false);
    setGameWon(false);
    setGameSolved(false);
    setWinningTeam([]);
  };
  
  const setGameType = (gameType) => {
    setGameSelected(gameType);
  };
  
  const rollPlayers = (startYear, endYear) => {
    axios.get(`/api/gettwoplayers?startYear=${startYear}&endYear=${endYear}`).then((res) => {
      setStartPlayer(res.data[0]);
      setEndPlayer(res.data[1]);
    });
  };
  
  const startTheGame = () => {    
    setGameStarted(true);
  };

  const goBackToGameSelection = () => {
    setGameSelected(false);
    setGameStarted(false);
    setStartPlayer("");
    setEndPlayer("");
  };

  const userSetPlayer = (player, type) => {
    if(type === "start") setStartPlayer(player);
    if(type === "end") setEndPlayer(player);
  };

  const theGameWasWon = (history) => {
    history.push(endPlayer);
    setWinningTeam(history);
    setGameWon(true);
  };

  const solveGame = () => {
    setGameSolved(true);
    axios.get(`/api/solve?startPlayer=${startPlayer}&endPlayer=${endPlayer}`).then((res) => {
      console.log(res.data);
    })
  };

  // 新增:提前计算要渲染的组件
  const renderComponent = () => {
    if (gameWon) {
      return <GameWon resetGame={resetGame} winningTeam={winningTeam} />
    }
    if (gameStarted) {
      return <GameScreen 
        startPlayer={startPlayer}
        endPlayer={endPlayer}
        gameWon={theGameWasWon}
        resetGame={resetGame}
        solveGame={solveGame}
      />
    }
    if (gameSelected === 'r') {
      return <CreateRandomGame 
        rollPlayers={rollPlayers} 
        startPlayer={startPlayer} 
        endPlayer={endPlayer}
        startTheGame={startTheGame}
        goBack={goBackToGameSelection}
      />
    }
    if (gameSelected === 's') {
      return <CreateUserGame
        startPlayer={startPlayer}
        endPlayer={endPlayer}
        userSetPlayer={userSetPlayer}
        startTheGame={startTheGame}
        goBack={goBackToGameSelection}
      />
    }
    return <ChooseGame setGameType={setGameType} />
  }

  return (
    <Container
      sx={{
        minHeight:'100vh',        
        maxWidth: "90vw!important",
      }}
    >
      {renderComponent()}
    </Container>
  );
}

export default App;

这个方案只需要新增一个renderComponent函数,原有所有状态、业务逻辑完全不用改,JSX部分直接清爽到只剩容器和一行渲染逻辑,后续加新状态只要在renderComponent里加判断分支就行,效率和可读性都比原有写法高很多。

方案2:有限状态机(适合后续要加大量新状态的场景)

如果后续还要加比如暂停、结算、排行榜之类的状态,可以用useReducer把所有游戏状态收敛成一个枚举值,完全避免多布尔状态混乱的问题:

  • 定义状态枚举:GAME_STATUS = { CHOOSE: 'choose', CREATE_RANDOM: 'create_random', CREATE_USER: 'create_user', PLAYING: 'playing', WON: 'won' }
  • 所有状态切换都通过dispatch触发,渲染的时候直接判断currentStatus的值就行,不会出现多个布尔值状态冲突的情况。

额外优化点

你现在的多个布尔状态其实很多是互斥的,比如gameWon为true的时候gameStarted、gameSelected肯定都不用判断,提前按状态优先级排序判断,还能减少不必要的校验逻辑,渲染效率更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 20:06:06