reactjs - How to reset multiple counters with one button in React
问题描述
The TLDR of my question is that each of my child components keeps and displays its own counter clicks. Each of those clicks also updates a Total
that is displayed. I'd like to know how to have the Reset
button to also have those children components reset.
I have an app that displays a total, a number of buttons that each increment the total in a different way and a reset button. In this small app weights is an array full of different weight objects
class CountersContainer extends React.Component {
constructor(props) {
super(props)
this.state = {
total: 0,
}
this.resetTotal = this.resetTotal.bind(this)
this.updateTotalByWeights = this.updateTotalByWeights.bind(this)
}
resetTotal = () => {
this.setState({
total: 0,
})
}
updateTotalByWeights = value => {
this.setState({
total: this.state.total + value * 2,
})
}
render() {
return (
<>
<div className="container">
{weights.map(w => (
<Weight
key={w.kg}
incrementTotal={this.updateTotalByWeights}
weight={w.kg}
/>
))}
</div>
<button className="click-target" onClick={this.resetTotal}>
reset
</button>
<WeightOutput total={this.state.total} units={this.state.metric} />
</>
)
}
/=============
// The weight component
/=============
import React from "react"
const Weight = ({ incrementTotal, weight }) => {
return (
<div onClick={() => { incrementTotal(weight) }} >
{weight}
</div>
)
}
export default Weight
This works fine. I'd like each Weight
component to keep count of the number of times its been clicked. So if the 5kg
weight component is clicked twice it will show a count of 2, along with updating the total in the desired fashion. So I added the following to my weight component:
import React, { useState } from "react"
const Weight = ({ incrementTotal, weight }) => {
const [count, setCount] = useState(0)
return (
<div
onClick={
() => {
incrementTotal(weight)
setCount(count + 1)
}
}
>
{count > 0 && <span>{count}</span>}
{weight}
</div>
)
}
export default Weight
This achieves the desired result of total being incremented correctly and the components count being updated each click.
However, now I need to change my reset button to reset each weight components count
and I'm completely at a loss for how to approach this. Some things I've considered are forcing each Weight to Re-render, keeping the "counts" further up the hierarchy. Perhaps a "hook" is the wrong implementation here (this little app is an attempt to get comfortable with hook primarily). Ideal answers will include both how to approach the problem along with potential solutions.
notes: I'm not sure that the above code is perfect, I've tried to strip out the parts that were not relevant to the question. Below I've added what the weight data looks like in case anyone is curious.
export const weights = [
{
color: "red",
kg: 25,
lbs: 55,
},
{
color: "blue",
kg: 20,
lbs: 45,
},
// this goes on a while.
UPDATE
I've updated my weight component to look like this:
import React, { useState, useEffect } from "react"
const Weight = props => {
const [count, setCount] = useState(0)
useEffect(() => {
setCount(0)
}, [props.reset])
return (
<div
onClick={() => {
props.incrementTotal(props.weight)
setCount(count + 1)
}}
>
{count > 0 && <span>{count}</span>}
{props.weight}
</div>
)
}
export default Weight
And added reset: 0
to my reset setState function. This hasn't solved my problem but does seem a promising direction per the React Hook Docs.
Update 2 I accepted the answer below because it was correct though I failed to understand it fully. In order to implement the below solution I had to update the "reset" value. I did this by passing.
I'm not sure this is a good solution. I believe it's re-rendering all weight components. Which potentially is bad, especially if there's a 1000 components that are complicated.
this.setState({
reset: !this.state.reset
})
解决方案
You can pass a prop with different value from parent to Weight
child components whenever you want to reset counters and use useEffect
hook with dependency as that prop. e.g
class Parent extends React.Component {
state = { reset: Date.now() };
resetCounters = () => {
this.setState({ reset: Date.now() });
}
render () {
<div>
<button onClick={this.resetCounters} >Reset</button>
<Wieght reset={this.state.reset} {..some other props} />
<Wieght reset={this.state.reset} {..some other props} />
<Wieght reset={this.state.reset} {..some other props} />
<Wieght reset={this.state.reset} {..some other props} />
</div>
}
}
const Weight = props => {
const [counter, setCounter] = useState(0);
useEffect(() => {
setCounter(0);
}, [props.reset]);
}
Another option is to pass reset
as key to Weight component so, on changing the key, it will remount. This is a simple solution but can cause performance issues for large number of Weight components
推荐阅读
- javascript - 验证消息隐藏在角度js中
- c# - 如何在忽略大小写 c# 的情况下检查枚举值中的“包含”?
- r - R:在数据直方图上叠加泊松分布
- xml - 在 C 程序中使用 libxml/xpath 在 XML 文件中查找和替换和属性
- ggplot2 - 如何使用带有 2 个变量和 3 个子变量的概率创建一个带有 ggplot 的 Bar
- swift - 如何在 Swift 中的导航链接期间更改变量的值?
- r - R:使用 formattable - 如何更改字体
- python-3.x - 如何在 Flask 和 Angular 8 中处理 GET 和 POST
- angular - 初始化函数是如何工作的?
- android - 来自范围存储的 Android 10 文件信息(从 Uri 获取文件扩展名)