在React Context API中共享类实例是否安全?

时间:2018-12-19 19:11:32

标签: javascript reactjs react-native react-redux

我正在React React中构建一个问答游戏,并使用Redux-Thunk来存储一个在游戏开始时创建的游戏对象。

它存储以下内容:

  • 游戏模式,玩家,问题,当前回合,当前玩家,当前问题(作为索引)

redux-thunk的问题在于处理不同的游戏模式和逻辑。

使用这样的游戏类是一种好习惯吗?

class Game {
  constructor() {
    Object.assign(this, DEFAULT_STATE);
  }

  init = (gamemode, players) => {
    // set Gamemode
    switch (gamemode) {
      case "classic":
        this.gamemode = new Classic();
        break;
    }
    // set Players
    this.players = players;

    // set Gameparameters
    this.parameters = this.gamemode.getGameParameters();

    // set Questions
    this.questions = this.gamemode.prepareQuestions();
  };

  // Getters
  getPlayerCount = () => this.players.length;
  getCurrentRound = () => this.currentRound + 1;
  getCurrentRoundIndex = () => this.currentRound;
}

并通过Context API在提供者中共享它以访问其状态和功能?

1 个答案:

答案 0 :(得分:1)

这是一个非常广泛的问题。我将就如何处理这种情况发表自己的看法。

自从React 16.3起,我发现内置的上下文api比Redux更易于使用,功能更强大。这就是我设置上下文提供程序的方式:

const DEFAULT_STATE = {
  gameMode: 'default',
  players: [],
  currentRound: 1,
  ...
};

export const MyContext = React.createContext(DEFAULT_STATE);
export const MyConsumer = MyContext.Consumer;

class MyProvider extends Component {
  state = DEFAULT_STATE;

  componentDidMount() {
    // query your api on app start here
  }

  render() {
    return (
     <MyContext.Provider
       value={{
         state: this.state,
         setState: (name, value, callback = () => {}) => {
           this.setState({ [name]: value }, callback);
         },
         incrementRound: () => {
           const { currentRound } = this.state;
           this.setState({ currentRound: currentRound + 1 });
         },
         // any other functions you want to expose to your consumer
       }}
     >
      {this.props.children}
     </MyContext.Provider>
  }
};

export default MyProvider;

然后您可以像这样设置您的根组件:

ReactDOM.render(
 <MyProvider><App /></MyProvider>,
 document.getElementById('root')
);

然后,您可以在任何其他组件中访问上下文/消费者:

class SomeComponent extends Component {
  state = {/* component state */};

  incrementRound = (context) => {
    // option a: access state directly
    const { currentRound } = context.state;
    context.setState('currentRound', currentRound + 1);
    // option b: expose function to handle state
    context.incrementState();
  };      

  render() {
    return (
      <section>
        <div>{/* some other stuff */}</div>
        <MyConsumer>
          {context => {
            const { currentRound } = context.state;
            return (
             <div>{currentRound}</div>;
             <button>Click to update round!</button>
            );
          }}
        </MyConsumer>
      </section>
    );
  }
}

这是一个非常简单的示例,但我认为这很重要。如果您走这条路线,我还建议您从DEFAULT_STATE对象中导出状态密钥,这样就不必使用文字字符串调用setState。您可以执行以下操作:

const stateKeysObj = {};
Object.keys(DEFAULT_STATE).forEach(key => {
  stateKeysObj[key] = key;
});
export const stateKeys = Object.freeze(stateKeysObj);

祝你游戏好运!