Как я могу улучшить условный рендеринг своих компонентов?

#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 for startTheGame и for goBack , потому что, когда я регистрирую его, он запускает функцию три раза с разными состояниями.

2. Я понял это, это были функции onclick, и мне нужно было сделать onClick={() => goBack("GAME_CHOICE")} это, чтобы иметь круглые скобки с функцией стрелки