What I am trying to do is update an array in state by adding a string of the name of the button the user pressed. The user has several buttons so after pressing them all I should be left with an array of strings correlating to the user's button presses.
First I give the user an alert telling them which food was added then I simply attempt to append the name of that food to the array in state. After which I pass that array back to the parent component to update a similar array there.
The problem I am getting is that when I press on one of the food options the array in state does not update, but i do get the correct alert. When I try a second food addition the array in state updates with the first option I selected. From then on every time I try to add a food Item the array in state updates with the food I selected before it.
I believe the problem is that I am updating state in a way that React does not do imminently. I know that state updates are not guaranteed in React.
Sorry for the long post, thank you for your time.
import React from "react";
import "./style.scss";
import FoodData from "./foodData.json";
class Food extends React.Component {
constructor(props) {
super(props);
this.state = {
foodData: [],
addedFoods: []
};
this.handleClick = this.handleClick.bind(this);
}
componentDidMount() {
// Build a new array of objects from FoodData
const newFoodData = FoodData.map(
({ name, pic, serving, calories, sugar, protien }, index) => ({
id: index,
name,
pic,
serving,
calories,
sugar,
protien
})
);
// Assign the new object to state
this.setState({ foodData: newFoodData });
}
handleClick(e) {
alert("Added " + e.target.name);
this.setState(
{
addedFoods: [...this.state.addedFoods, e.target.name]
},
this.props.updateAddedFoods(this.state.addedFoods)
);
}
render() {
const displayFood = () => {
let foodItems = []; // Crate an array
for (let i = 0; i < this.state.foodData.length; i++) {
foodItems.push(
// push item to array through the loop
<div className="food-card" key={i}>
<img src={require(`${this.state.foodData[i].pic}`)} />
<ul>
<li>{this.state.foodData[i].name}</li>
<li>Serving: {this.state.foodData[i].serving}</li>
<li>Calories: {this.state.foodData[i].calories}</li>
<li>Sugar: {this.state.foodData[i].sugar}</li>
<li>Protien: {this.state.foodData[i].protien}</li>
</ul>
<button
onClick={this.handleClick}
name={this.state.foodData[i].name}
>
Add
</button>
</div>
);
}
return foodItems;
};
return (
<div>
<div className="food-container">
{!this.state.foodData.length ? <h1>Loading ...</h1> : displayFood()}
</div>
</div>
);
}
}
export default Food;
Second argument for setState
should be a function and not a function call. Also it is better to use setState(oldState => newState)
when new state is based on the old one:
handleClick(e) {
const name = e.target.name;
alert("Added " + name);
this.setState(oldState => ({
addedFoods: [...oldState.addedFoods, name]
}),
() => this.props.updateAddedFoods(this.state.addedFoods)
);
}