boardgame.io icon indicating copy to clipboard operation
boardgame.io copied to clipboard

stop destructuring state on the React client

Open nicolodavis opened this issue 5 years ago • 6 comments

We currently destructure the state object on the React client: source.

This allows you to access G as props.G rather than having to do props.state.G. However, it does cause name clashes between properties in the game state and other props that are passed to the React client (for example plugins).

The proposal is to stop destructuring the state object.

nicolodavis avatar May 02 '20 09:05 nicolodavis

One thing that could be confusing about this is that state means something in React, so props.state is confusing. We'd have to rename it to something like gameState, which could also be confused with just the user-controlled game state G.

nicolodavis avatar May 02 '20 09:05 nicolodavis

Maybe use a sort of namespace instead of state? Something like bgio?

adngdb avatar May 02 '20 09:05 adngdb

I personally don’t mind overly the fact that props.state is similar to the React naming convention. It’s most confusing in class components where you could have this.state and props.state, but with function components it’s less likely there will be a variable actually named state.

This is also a prop that will very likely be destructured early in the component tree, so users will likely not be passing a state prop between lots of components. In fact, I would suggest showing something like this in documentation:

function Board (props) {
  const { G, ctx } = props.state;
  return (
    <div>
      <Score value={G.score} />
      <TurnCounter count={ctx.turn} />
    </div>
  )
}

If you do think an alternative name is essential, might store be viable?

It might also make sense to discuss how to structure namespaces for plugins more generally before deciding for sure. Currently the situation we’re trying to resolve is:

{
  plugins: {}, // plugin data
  plugins: {}, // plugin dispatchers
}

If we add support for client plugins as briefly mentioned in #632, we might end up with a third plugins namespace. This RFC would resolve the current conflict, but how would we resolve that?

Instead of using plugins.chat() for the action dispatchers, perhaps we should use an explicit dispatch namespace freeing up plugins for other API details:

client.dispatch.chat({ message: 'Hello world!' })

delucis avatar May 02 '20 13:05 delucis

Another question around the interface for plugins on the client:

Currently state is available at plugins[name].data, which mirrors the data/api distinction of plugins, but if we’re not going to combine these on the client — e.g. { data, dispatch, ...etc } — the data namespace might be unnecessarily verbose. state.plugins[name] should probably point directly to the data.

delucis avatar May 06 '20 08:05 delucis

Re: the state destructuring, you could get the best of both worlds, by pre-destructuring the state fields you want as top-level properties (like G, ctx, isActive, and isConnected?) and passing those explicitly, and allowing the others to pass as something like gameState:

      if (board) {
        const { G, ctx, isActive, isConnected, ...gameState } = state;
        _board = React.createElement(board, {
          // ...state,        // <=== removed
          ...this.props,
          G,                  // <=== added
          ctx,                // <=== added
          isActive,           // <=== added
          isConnected,        // <=== added
          gameState,          // <=== added, all "other" state
          isMultiplayer: !!multiplayer,
          moves: this.client.moves,
          events: this.client.events,
          gameID: this.client.gameID,
          playerID: this.client.playerID,
          reset: this.client.reset,
          undo: this.client.undo,
          redo: this.client.redo,
          log: this.client.log,
          gameMetadata: this.client.gameMetadata,
        });
      }

I'm still very new to using boardgame.io, so I defer to you as to which values are "worthy" of being escalated to top-level props, and which ones should stay under gameState.

JaredReisinger avatar Jun 04 '20 20:06 JaredReisinger

I would heavily object to keeping it as props.state:

  const { G, ctx } = props.state;
  const { a, b } = state;

It seems like it would be confusing for beginners and easy to mess the two up during brief glances of a code base. Knowing whether something is coming from state or props is really important in React contexts.

popey456963 avatar Aug 24 '20 21:08 popey456963