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
相关产品推荐
相关产品推荐

