Reputation: 739
I'm currently developing a React app (ES6) whereby a number of food items will be listed.
Each time a product has been clicked, the individual product count (child state) should increase by 1 each time, which currently works.
However, the total calorie count (parent state) should also increase using the data from the parent foods state.
Example: A user clicks on the Brussel Sprouts item. The FoodItem count will increase by +1 on each click, however I also require the overall calorie count in the App class (this.state.calorieCount) to increment, by 28.1 on each click in this instance.
I'm fairly new to react so any help on this would be much appreciated.
// FoodCards.js
const FoodCards = [
{
id: 0,
name: 'Brussel Sprouts',
quantity: '1/2 cup',
calories: 28.1,
betacarotene: 0.363,
bilberry_fruit: 0,
curcumin: 0,
grapeseed: 0,
green_tea: 0,
lutein: 1,
lycopene: 0,
vitamin_a: 0.03,
vitamin_d: 0
},
...
];
export default FoodCards
// App.js
import React from 'react';
import './tailwind.output.css';
import './App.scss';
import FoodCards from './data/foods';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
foods: FoodCards,
calorieCount: 0,
vitaminACount: 0,
vitaminDCount: 0,
};
this.increment = this.increment.bind(this);
}
increment(calories, vitaminA, vitaminD) {
this.setState({
calorieCount: Math.round(this.state.calorieCount + calories),
vitaminACount: Math.round((this.state.vitaminACount + vitaminA) * 100) / 100,
vitaminDCount: Math.round((this.state.vitaminDCount + vitaminD) * 100) / 100
});
};
reset() {
this.setState({
calorieCount: 0,
vitaminACount: 0,
vitaminDCount: 0,
});
};
render() {
return (
<div className="App">
<header className="flex flex-wrap">
<div className="calories-total">
<span>Calories</span>
<span className="num">{this.state.calorieCount}</span>
</div>
<div className="vitamin-a-total">
<span>Vitamin A</span>
<span className="num">{this.state.vitaminACount}</span>
</div>
<div className="vitamin-d-total">
<span>Vitamin D</span>
<span className="num">{this.state.vitaminDCount}</span>
</div>
<div className="export-btn flex items-center justify-center">
Export Full Report
</div>
</header>
<main className="products-grid flex flex-wrap">
{this.state.foods.map((item, i) => {
return <FoodItem key={item.id} name={ item.name } calories={item.calories} />
})}
</main>
<footer>
<div className="reset" onClick={() => this.reset()}>Reset</div>
</footer>
</div>
);
}
}
export default App;
class FoodItem extends React.Component {
constructor(props) {
super(props);
this.state = {
clickCount: 0
};
}
handleClickIncrement() {
this.setState({
clickCount: this.state.clickCount + 1
});
};
render() {
return (
<div className="product" onClick={() => this.handleClickIncrement()}>
<p>{this.props.name} - {this.state.clickCount}</p>
<p>Calories: {this.props.calories}</p>
</div>
);
}
}
Upvotes: 0
Views: 40
Reputation: 613
Your FoodItem needs a function with which it can notify the parent. So in App you can give it something like this:
<FoodItem
updateParent={this.updateFromItem.bind(this)}
// other props
/>
Also in the Parent
updateFromItem(calories) {
this.increment(calories, 0, 0);
}
The updateFromItem
function sits within the parent component and via bind(this)
it is scoped to it, but you propagate the change from the child (FoodItem) and call it from there:
handleClickIncrement() {
this.props.updateParent(this.props.calories);
// ...
}
Upvotes: 2