将状态设置器传递给多个组件?

时间:2020-04-25 19:40:43

标签: javascript reactjs react-hooks

我有以下代码;

export default () => {
    const [gameState, setGameState] = useState(GameStateMap.MAINMENU);
    const getGameComponent = useMemo(() => {
        switch (gameState) {
            case "MainMenu":
                return <MainMenu />
            case "Game":
                return <Game />
            case "GameOver":
                return <GameOver />
            default:
                throw new Error("Invalid Component");
        }
    })
    return (
        <Wrapper>
            {getGameComponent}
        </Wrapper>
    )
}

我打算让MainMenuGameGameOver都可以访问setGameState。我最好的选择只是将setGameState依次传递给每个游戏,还是有更常规的选择?

2 个答案:

答案 0 :(得分:0)

当前,您调用<MainMenu/>),然后分配(getGameComponent =

您应该分配,然后调用,然后可以向其传递道具:

export default () => {
  const [gameState, setGameState] = useState(GameState.MAINMENU);

  // Component should be Uppercased
  const GameComponent = useMemo(() => {
    switch (gameState) {
      case "MainMenu":
        return MainMenu;
        break;
      case "Game":
        return Game;
        break;
      case "GameOver":
        return GameOver;
        break;
      default:
        throw new Error("Invalid Component");
    }
  });
  return (
    <Wrapper>
      <GameComponent onGameStateChange={setGameState} />
    </Wrapper>
  );
};

更好地重写此组件(有意见)可能是:

const GAME_STATE = {
  MainMenu: MainMenu,
  Game: Game,
  GameOver: GameOver,
};

export default () => {
  const [gameState, setGameState] = useState(GameState.MAINMENU);

  const GameComponent = GAME_STATE[gameState];

  // Better show error in the UI and not a runtime exception.
  return (
    <Wrapper>
      {GameComponent ? (
        <GameComponent onGameStateChange={setGameState} />
      ) : (
        `No such game state`
      )}
    </Wrapper>
  );
};

答案 1 :(得分:0)

关于这一方面有两种思想流派。第一种叫做螺旋钻,这是您在原始问题中建议做的。第二个是使用React Context。我过去都用过。两者都有好处和缺点。我更喜欢使用上下文。但是,这是我的看法。

这里是一篇文章,解释了两者之间的区别。 https://medium.com/@jtonti/context-vs-prop-drilling-in-react-aa88fff7cd44

关于操作方法,请参见下文。

    // in App.js or your main page
    export default () => {
        const [gameState, setGameState] = useState(GameStateMap.MAINMENU);
        const getGameComponent = useMemo(() => {
            switch (gameState) {
                case "MainMenu":
                    return <MainMenu setGameState={setGameState} />
                case "Game":
                    return <Game setGameState={setGameState}  />
                case "GameOver":
                    return <GameOver setGameState={setGameState}  />
                default:
                    throw new Error("Invalid Component");
            }
        })
        return (
            <Wrapper>
                {getGameComponent}
            </Wrapper>
        )
    }

    // in MainMenu
    ...
    const {setGameState} = props // or this.props if using classes
    // code to use setGameState
    ...

用于使用上下文

// in app.js
const AppContext = React.CreateContext();
export default () => {
    const [gameState, setGameState] = useState(GameStateMap.MAINMENU);
    const getGameComponent = useMemo(() => {
        switch (gameState) {
            case "MainMenu":
                return <MainMenu />
            case "Game":
                return <Game />
            case "GameOver":
                return <GameOver />
            default:
                throw new Error("Invalid Component");
        }
    })
    return (
        <Wrapper>
            <AppContext.Provider value={{setGameState}}>
            {getGameComponent}
            </AppContext.Provider>
        </Wrapper>
    )
}

// in MainMenu
... 
const {setGameState} = useContext(AppContext);
...