TrivialCase
TrivialCase

Reputation: 1099

Individual handling of multiple components

I have a simple game app I'm trying to put together as an exercise:

  1. user clicks toggle the Buttons for selection (i.e. choose all correct answers)
  2. the selection map gets submitted to the game
  3. if the selection map is correct increase Timer.timeRemaining by N seconds, else decrease Timer.timeRemaining by M seconds.

I thought it seemed easy enough, but in step 1 when I change the button properties (which you can see are an object mapped to each button name/id, maybe not the way to do this?) it does not update the props of Button so I don't get a re-render.

Is there a standard way that I should be doing this? Prefer to try to do it in React without resorting to Redux yet (if that was an option) since I haven't really learned it (although it is coming up in the book I'm reading through, so if that's necessary to maintain state of the whole game here...).

Relevant part of the code:

ButtonProp class:

class ButtonProp {
  constructor(selected = false, style = { backgroundColor: '#1051c5', color: '#fff' }) {
    this.isSelected = selected;
    this.hasStyle = style;
    this.unselectedStyle = {
      backgroundColor: '#1051c5',
      color: '#fff'
    };
    this.selectedStyle = {
      backgroundColor: '#c1ecff',
      color: '#999'
    };
  }
  toggle() {
    [this.isSelected, this.hasStyle] = this.isSelected
      ? [false, this.unselectedStyle]
      : [true, this.selectedStyle];
  }
}

The class that makes the actual game (called by a separate class called TestGame, which passes the props, which look like ['A', 'B', 'C', 'D', 'E']):

class TestGameMaker extends Component {
  constructor(props) {
    super(props);
    let buttonMapArray = [];
    props.choices.map((choice) => {
      buttonMapArray = [...buttonMapArray, [choice, new ButtonProp()]];
    });
    const buttonMap = new Map(buttonMapArray);
    this.interval = 0;
    this.state = {
      buttons: buttonMap,
      timeRemaining: 10
    };
    this.selectHandler = this.selectHandler.bind(this);
  }
  submitHandler(e) {
    // Check if the currentSelection array matches the answer
  }
  selectHandler(e) {
    // change the color/background color of the selected button
    // toggle currentSelection array entry to true/false
    this.state.buttons.get(e.target.id).toggle();
  };
  render() {
    return (
      <div>
        <Timer timerValue={this.state.timeRemaining} />
        {this.props.choices.map(
          choice => (
            <Button
              key={choice.id}
              name={choice}
              style={this.state.buttons.get(choice).hasStyle}
              handler={this.selectHandler}
            />
          )
        )}
        <Submit handler={this.submitHandler} />
      </div>
    );
  }
}

TestGameMaker.propTypes = {
  choices: PropTypes.arrayOf(PropTypes.string).isRequired
};

Upvotes: 2

Views: 62

Answers (1)

Jake Haller-Roby
Jake Haller-Roby

Reputation: 6427

You're pretty far off from how react is meant to work. It looks like you're trying to closely follow OOP principles, but React is much more of a functional framework.

That toggle method ought to exist on the TestGameMaker component. It ought to modify the state of that component using setState. The button component ought to pull it's props from the TestGameMaker state.

I would recommend going through one of the simple react ToDo tutorials and pay special attention to the purpose of the component state.

Upvotes: 1

Related Questions