Reputation: 739
I currently have a parent class (App) and a child component (FoodItem). The App component maps a list of FoodItem components.
Each individual FoodItem component has a state called clickCount which increments each time its clicked by the user. However, I need the reset button in my App component to reset the FoodItem state to 0 onClick for all FoodItem components in the map.
Any help with this would be much appreciated.
Update - I have managed to get the reset button to update the FoodItem child component, however it only updates the last item in the mapped list, whereas I require it to update all items in the list.
class App extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
this.state = {
foods: FoodCards,
calorieCount: 0,
vitaminACount: 0,
vitaminDCount: 0,
};
this.increment = this.increment.bind(this);
}
increment = (calories = 0, vitaminA = 0, vitaminD = 0) => {
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
});
};
resetCounters = () => {
this.myRef.current.resetClickCount();
this.setState({
calorieCount: 0,
vitaminACount: 0,
vitaminDCount: 0,
});
};
render() {
return (
<div className="App">
<main className="products-grid flex flex-wrap">
{this.state.foods.map((item, i) => {
return <FoodItem key={item.id} ref={this.myRef} name={item.name} img={item.img} calories={item.calories} vitamin_a={item.vitamin_a} vitamin_d={item.vitamin_d} updateTotals = {this.increment} />
})}
</main>
<footer>
<div className="reset" onClick={() => this.resetCounters()}>Reset</div>
</footer>
</div>
);
}
}
export default App;
class FoodItem extends React.Component {
constructor(props) {
super(props);
this.state = {
clickCount: 0
};
}
handleUpdateTotals = (calories, vitamin_a, vitamin_d) => {
this.props.updateTotals(calories, vitamin_a, vitamin_d);
this.clickIncrement();
}
clickIncrement = () => {
this.setState({
clickCount: this.state.clickCount + 1
});
}
resetClickCount = () => {
this.setState({
clickCount: 0
});
}
render() {
return (
<div className="product" onClick={() => this.handleUpdateTotals(this.props.calories, this.props.vitamin_a, this.props.vitamin_d)}>
<p>{this.props.name}</p>
{this.state.clickCount > 0 ? <p>Selected: {this.state.clickCount}</p> : <p>Not Selected</p>}
<img src={this.props.img} alt="" />
</div>
);
}
}
Upvotes: 0
Views: 88
Reputation: 5345
You should lift the state up per the react docs. When two children affect the same state (reset button and clickCount), the state should be lifted up to the parent that contains both of these children. So your count should be stored in the parent.
But... to answer your question, you can easily do something like this to trigger a render each time the button is clicked (not recommended though):
const [resetCount, setResetCount] = useState(false);
const resetCountClicked = () => setResetCount(!resetCount);
return
<>
<Child resetCount={resetCount}></Child>
<button onClick={() => resetCountClicked()}>Reset Count</button>
</>
And in the child include:
useEffect(() => setCount(0), [resetCount]);
This is using hooks with function components and useEffect
to run an event each time the prop resetCount
changes.
With classes you can use a ref passed to the child as shown in this post.
const { Component } = React;
class Parent extends Component {
constructor(props) {
super(props);
this.child = React.createRef();
}
onClick = () => {
this.child.current.resetCount();
};
render() {
return (
<div>
<Child ref={this.child} />
<button onClick={this.onClick}>Reset Count</button>
</div>
);
}
}
And in the child...
resetCount() {
this.setState({
clickCount: 0
});
}
Upvotes: 1