#reactjs #conditional-rendering
#reactjs #условный рендеринг
Вопрос:
У меня есть много компонентов, которые визуализируются на основе разных состояний, которые я использую для игры. В настоящее время я использую метод, в котором я проверяю значение состояния с помощью амперсандов. Я не уверен, есть ли другой способ, которым я должен это сделать, или есть более эффективный и чистый способ сделать это.
Я просмотрел несколько разных способов, но мне было интересно, может ли кто-нибудь дать мне предложения по чему-то, что будет хорошо работать с моим существующим кодом.
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}amp;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}amp;endPlayer=${endPlayer}`).then((res) => {
console.log(res.data);
})
};
return (
<Container
sx={{
minHeight:'100vh',
maxWidth: "90vw!important",
}}
>
{
!gameSelected amp;amp;
!gameStarted amp;amp;
!gameWon amp;amp;
<ChooseGame setGameType={setGameType} />
}
{
!gameStarted amp;amp;
!gameWon amp;amp;
gameSelected === 'r' amp;amp;
<CreateRandomGame
rollPlayers={rollPlayers}
startPlayer={startPlayer}
endPlayer={endPlayer}
startTheGame={startTheGame}
goBack={goBackToGameSelection}
/>
}
{
!gameStarted amp;amp;
!gameWon amp;amp;
gameSelected === 's' amp;amp;
<CreateUserGame
startPlayer={startPlayer}
endPlayer={endPlayer}
userSetPlayer={userSetPlayer}
startTheGame={startTheGame}
goBack={goBackToGameSelection}
/>
}
{
!gameWon amp;amp;
gameStarted amp;amp;
<GameScreen
startPlayer={startPlayer}
endPlayer={endPlayer}
gameWon={theGameWasWon}
resetGame={resetGame}
solveGame={solveGame}
/>
}
{
gameWon amp;amp;
<GameWon
resetGame={resetGame}
winningTeam={winningTeam}
/>
}
</Container>
);
}
export default App;
Комментарии:
1. Для удобства вы можете использовать троичные операторы
Ответ №1:
Две вещи, которые вы могли бы попробовать:
Во-первых, у вас много boolean
состояний, например gameStarted
, и многие из них кажутся взаимоисключающими с другими логическими состояниями, например, gameStarted
похоже, что это никогда не может быть true
одновременно с gameWon
. В подобных ситуациях может быть намного лучше моделировать состояние как перечисляемый тип; к сожалению, в Javascript их нет изначально (посмотрите в TypeScript для «истинного» enum
типа), но мы можем обойтись строками:
const MODE_STARTED = 'started'
const MODE_SELECTED_RANDOM = 'random'
const MODE_SELECTED_USER = 'user'
const MODE_GAME_WON = 'won'
...
const [gameMode, setGameMode] = useState(MODE_STARTED);
...
Теперь вместо того, чтобы перелистывать отдельные логические значения повсюду, вы можете просто изменить режим игры … например setGameMode(MODE_SELECTED_RANDOM)
Как только вы это сделаете, ваш JSX тоже может стать чище:
const showCorrectUI = () => {
switch (gameMode) {
case MODE_STARTED:
return <GameScreen {foo} />
case MODE_GAME_WON:
return <GameWon {bar} />
... // etc
}
}
return (
<Container
sx={{
minHeight:'100vh',
maxWidth: "90vw!important",
}}
>
{showCorrectUI()}
</Container>)
Комментарии:
1. Итак, я пытаюсь это сделать, и при визуализации нового компонента вызывается моя функция setgamestate. Например
case RANDOM_GAME_SELECTED: return <CreateRandomGame rollPlayers={rollPlayers} startPlayer={startPlayer} endPlayer={endPlayer} startTheGame={changeGameState} goBack={changeGameState} />;
, он отображает этот код, затем вызываетchangeGameState
forstartTheGame
и forgoBack
, потому что, когда я регистрирую его, он запускает функцию три раза с разными состояниями.2. Я понял это, это были функции onclick, и мне нужно было сделать
onClick={() => goBack("GAME_CHOICE")}
это, чтобы иметь круглые скобки с функцией стрелки