can someone tell me why is this “upvote” onClick handler firing twice? the logs would indicate it’s only running once but the score it controls increases by 2
export default class Container extends Component { constructor(props) { super(props); this.state = { jokes: [], }; this.getNewJokes = this.getNewJokes.bind(this); this.retrieveJokes = this.retrieveJokes.bind(this); this.upVote = this.upVote.bind(this); } upVote(id) { this.setState(state => { //find the joke with the matching id and increase score by one const modifiedJokes = state.jokes.map(joke => { if (joke.id === id) { joke.score = joke.score + 1; } return joke; }); console.log(modifiedJokes); return { jokes: modifiedJokes }; }); } render() { return ( <div> <h1>Container</h1> {this.state.jokes.map(joke => ( <Joke key={joke.id} id={joke.id} joke={joke.joke} score={joke.score} upVote={this.upVote} downVote={this.downVote} /> ))} </div> ); } }
on the other hand if I rewrite the handler this way, then it fires only once
upVote(id) { const modifiedJokes = this.state.jokes.map(joke => { if (joke.id === id) { joke.score = joke.score + 1; } return joke; }); this.setState({ jokes: modifiedJokes }); };
Advertisement
Answer
My best guess is that in the first case, you are also modifying the state directly, when you do joke.score = joke.score + 1;
Because you are doing this mapping directly on state array variable, and in Javascript, when using array, you are only working with pointer to that array, not creating a copy of that array.
So the mapping function probably takes a shallow copy of the array, and there’s where problem happens.
You can use lodash to create a deep copy of the state array before you going to work with it, which will not cause your problem: