1
votes

When this component is called I get the follow error.

setState(...): Cannot update during an existing state transition (such as within render or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to componentWillMount.

It seems to be because { this.renderCurrentAthlete() } inside render. When I call renderCurrentAthlete I'm trying to let state know who the current Athlete is by running the this.setState({ currentAthlete: currentAthleteData.Athlete }) but it causes an error. Any advise on how to handle this properly? Also any other advise on the component would be awesome too! Learning so all info is a great help :)

class MiniGame extends Component {
  constructor(props){
    super(props);
    this.state = {
        score: 0,
        currentAthlete: null
    }
  }

gameData = [
        {Athlete: "Peyton Manning", Img: "someURL"},
        {Athlete: "Tony Hawk", Img: "someURL"},
        {Athlete: "Tomy Brady", Img: "someURL"},
        {Athlete: "Usain Bolt", Img: "someURL"}
]

renderGameButtons() {
    return(
        <div>
            {this.gameData.map((x) => { 
                return(
                    <div key={x.Athlete}>
                        <button className="btn btn-outline-primary" onClick={ () => this.answerHandler(x.Athlete)}> {x.Athlete} </button>
                    </div>
                ) 
            })}
        </div>
    )
}

renderCurrentAthlete() {
    const currentAthleteData = this.gameData[Math.floor(Math.random() * 4)];
    //console.log(currentAthleteData);
    const imgUrl = currentAthleteData.Img;
    const athleteName = currentAthleteData.Athlete;
    console.log(imgUrl, athleteName);
    //console.log(currentAthlete);
    this.setState({ currentAthlete: currentAthleteData.Athlete });
    return(
        <img className="card-img-top imgCard" src={imgUrl} alt="..."></img>
    )
}

answerHandler(answer){
    // console.log(a)
    // console.log(this.state.currentAthlete)
    if(answer === this.state.currentAthlete) {
        this.setState({score: this.state.score + 10})
        console.log(this.state.score);
    }
}

render(){
    return(
        <div className="miniGameContainer">
            <div className="card card-outline-info  mb-3">
                { this.renderCurrentAthlete() }
                <div className="card-block">
                    <p className="card-text">Pick your Answer Below</p>
                        { this.renderGameButtons() }
                </div>
            </div>
        </div>
    )
  }
}
1
why would you want to setstate for currentAthlete , I don't see you using it - Shubham Khatri
It doesn't seem to like the state transition in the render block because React automatically updates the DOM via the state, and setting the state in render is probably not a good thing. Maybe try taking this.renderCurrentAthlete out and putting it in a react lifecycle method like componentDidMount() or the one it suggested, and then calling this.renderCurrentAthlete() from that lifecycle method? - Dream_Cap

1 Answers

1
votes

Add method componentWillMount put this code to it and remove from renderCurrentAthlete. method componentWillMount will invoke before render. See more react lifecycle

componentWillMount() {
 const currentAthleteData = this.gameData[Math.floor(Math.random() * 4)];
    //console.log(currentAthleteData);
    const imgUrl = currentAthleteData.Img;
    const athleteName = currentAthleteData.Athlete;
    console.log(imgUrl, athleteName);
    //console.log(currentAthlete);
    this.setState({ currentAthlete: currentAthleteData.Athlete });
}