How do you update the Parent State using a Child Component (Simon Game)?

I’m working on the Simon Game project and having trouble updating the parent state via a method defined on the child component.

Here is the pen:
https://codepen.io/codemamba/pen/gJPepG?editors=0010

The child component has this method defined.

  chooseRandomColor() {
    let randomColor = this.props.colors[Math.floor(Math.random()*4)]; //4 bc 4 colors
    alert(randomColor);
    
    this.pressColor(randomColor);
    **this.props.handleStateChange(randomColor)**
  }

This method works fine except for the last line where it calls this.props.handleStateChange.

this.props.handleStateChange(randomColor) is the method that should update the parent state.
It’s supposed to use props to pass the randomColor variable into a handleStateChange function defined on the parent state.

The parent component looks like this:

class SimonGame extends React.Component {
 constructor(props) {
   super(props);
    this.state = {
      colors: ['red', 'green', 'yellow', 'blue'],
      **storedMoves: [],**
      userMoves: []
    }
   this.handleStateChange = this.handleStateChange.bind(this)
 }
  
 **handleStateChange(randomColor)** {
    alert('changing the state ' + randomColor);
    this.setState({ 
      storedMoves: [...storedMoves, randomColor]
    })
 }

  render() {
    return (
      <SimonCircle colors={this.state.colors} handleStateChange={this.handleStateChange} />
    )
  }
}

So chooseRandomColor runs when Start is clicked, and it’s supposed to call this.props.handleStateChange(randomColor) which should run handleStateChange(randomColor) as defined on the parent state, but it’s not working. No alert occurs nor does it update the storedMoves array in State.

Do you have any idea why?

You need to look at the browser console. It is telling you about an error you need to resolve. Once you fix that, you will get a new error which you will need to resolve.

you also do not need to use this.handleStateChange = this.handleStateChange.bind(this) if you change you function to an arrow function like

const handleStateChange = (randomColor) => {
    alert('changing the state ' + randomColor);
    this.setState({ 
      storedMoves: [...storedMoves, randomColor]
    })
 }

Thanks for the tip! I didn’t think of that since I’m still new to React. Went into Debug mode and fixed the two errors. Can’t believe I forgot to prefix storedMoves with this.state. It works now. :slight_smile:

is it considered better practice to do this as opposed to bind(this)?

Thanks, I decided to change the structure based on your advice.

Could you take a look at the new version?

https://codepen.io/codemamba/pen/rgxPXb?editors=0010

Thanks so much for the help, it’s been really helpful to a React beginner like myself. I’m currently working on figuring out the rest of the game. Hope you don’t mind me asking for help if I run into other issues.

Thanks again for helping me get started.

I’ve finished the game, and re-designed it. Could you take a look at it?

https://codepen.io/codemamba/pen/VOKgYX

One thing I notice about the game is that it does not give alert you to the fact that you have gotten a sequence wrong until you have pressed the same number of buttons as the level you are on. For example, if I were on level 5 and the following was the simon sequence: Blue, Blue, Yellow, Red, Green and the first button I press is Red, it should go ahead and restart the correct sequence and not wait until I press 4 more buttons.

Ah, good catch. I thought the game was supposed to wait for the user’s turn to be over before checking. It currently only checks after each click in Strict mode.

#2) You should use destructuring to make your code cleaner (i.e. avoid write this.state over and over)

Does destructuring have to be done within each method? Or can you declare it once for an entire component.

For example, can you declare const {readyForUserInput, strictMode} = this.state; for an entire component such that all methods can access them, or do you have to declare it each time within each method?

#3) I recommend not having more than one nested ternary statement. You pass the following className prop to the SimonCircle component:

What would be an alternate way to write it? I couldn’t figure out if there was a way around nesting ternary operators. IF/IElse If statements can’t be used in this case right.