I am new to React, so I apologize in advance if I'm trying to do something that cannot be done. I am trying to store an object containing an id and a score for a selection in a "scores" array in the state. I am building the object in a function called handleScore, and the state seems to be showing properly when I first click on the selection and log the score array to the console immediately afterward, but when I log the score array to the console in the render method, I'm just getting a 1. I also get a 1 when I make a selection then click the button again. Does anyone have any ideas what's going on? Here is the code:
handleScore = (id, score, idx) => {
const { statements, scores } = this.state;
let scoreObj = {};
Object.assign(scoreObj, {'id': id, 'score': score});
if (statements[0][idx].isSelected) {
this.setState({
scores: scores[0].push(scoreObj)
});
console.log("scores array: ", scores[0]); //outputs an array containing [{id: "O1", score: "4"}]
} else {
console.log("scores array: ", scores[0]); // outputs 1
}
}
In the render() method:
render() {
console.log("this.state.scores from render method: ", this.state.scores); // outputs 1 instead of [{id: "O1", score: "4"}]
return (
<div>
<div className="statements-wrapper">
{
this.state.statements[0].map((item, index) => (
<div
key={item.id} onClick={(e) => {
e.preventDefault();
this.handleScore(item.id, match.params.score, index)
}}>
<a href="#">{item.statement}</a>
</div>
)
)
}
</div>
</div>
)
expected output:
scores: [
[{id: "O1", score: 4}, {id: "G1", score: 3}, {id: "B1", score: 2}, {id: "R1", score: 1}],
[{id: "O2", score: 4}, {id: "G2", score: 3}, {id: "B2", score: 2}, {id: "R2", score: 1}],
[{id: "O3", score: 4}, {id: "G3", score: 3}, {id: "B3", score: 2}, {id: "R3", score: 1}],
[{id: "O4", score: 4}, {id: "G4", score: 3}, {id: "B4", score: 2}, {id: "R4", score: 1}],
[{id: "O5", score: 4}, {id: "G5", score: 3}, {id: "B5", score: 2}, {id: "R5", score: 1}]
]
I think the problem stems from replacing the entirety of this.state.scores
to a single array when you use setState
. To preserve the rest of the element arrays, you want to do something like:
handleScore = (id, score, idx) => {
const { statements, scores } = this.state;
if (statements[0][idx].isSelected) {
// this assumes you want to append the first array (hence 'index === 0') in this.state.scores
this.setState({
scores: scores.map((item, index) => index === 0 ? [...item, {'id': id, 'score': score}] : item)
});
}
}
It's also important to note that the method above as well as push
will put the new object at the end of the array and that setState
is asynchronous, so console logging scores
immediately afterward may not be reliable.
To remove a specific object within one of the inner arrays, you can use filter:
// replacing an inner object by id value
scores.map((item, index) => index === 0 ?
item.filter((i) => i.id !== "01")
: item
)