2

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 }; 

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

5 Comments

I had originally had that behavior, the problem came that I couldn't figure out how to get the tougher to only toggle the button that was clicked, it would toggle all of them. This was an attempt to fix that problem that seems to have gone awry. So if you move it inside, do you just have N different states for whether a button is selected? And if so, what if the number of possible choices isn't a fixed value?
So you want a data type that represents N distinct values of the same type, which can grow and shrink in size dynamically, and be referenced by some sort of key or index.... Sounds like an array, wouldn't you say?
Yes, I started that way, but then I was passing the index to the Buttons as id so that I could change the correct entry in the array of selections, which seemed like an extra step. Thus the maps instead. But I guess in hindsight that was more work anyway.
You really ought to just curry the handler functions with the id value, so that you can create and pass functions which already know which index to update.
Your comments have been very very helpful, thank you! Currying is much neater, I'm just not used to think of that. And using an array works nicely now. I'm new enough to functional paradigm that I don't think entirely like that yet.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.