React Hooks 如何处理多个状态的并发更新?
在下面的代码中,我通过使用唯一的全局“State”来处理多个状态变量的并发更改,但我认为这不是最好的方法。
有人可以建议我如何更改多个状态而不像我一样将它们保持在一起吗?
这是具有“复杂状态”的工作代码
import { useState } from 'react'
const App = () => {
const [state, setState] = useState({
good: 0,
neutral: 0,
bad: 0,
tot: 0,
weights: 0,
avg: 0,
posPercent: 0
});
const handleGood = () => {
setState({
...state,
good: state.good +1,
tot: state.tot +1,
weights: (state.good+1)*1 + state.neutral*0 + state.bad*(-1),
avg: ((state.good+1)*1 + state.neutral*0 + state.bad*(-1))/(state.tot +1),
posPercent: ((state.good+1)*100)/(state.tot+1)
});
}
const handleNeutral = () => {
setState({
...state,
neutral: state.neutral +1,
tot: state.tot +1,
weights: state.good*1 + (state.neutral+1)*0 + state.bad*(-1),
avg: (state.good*1 + (state.neutral+1)*0 + state.bad*(-1))/(state.tot +1),
posPercent: ((state.good)*100)/(state.tot+1)
});
}
const handleBad = () => {
setState({
...state,
bad: state.bad +1,
tot: state.tot +1,
weights: state.good*1 + state.neutral*0 + (state.bad+1)*(-1),
avg: (state.good*1 + state.neutral*0 + (state.bad+1)*(-1))/(state.tot +1),
posPercent: ((state.good)*100)/(state.tot+1)
});
}
return (
<div>
<h1>give feedback</h1>
<button onClick={handleGood}>
good
</button>
<button onClick={handleNeutral}>
neutral
</button>
<button onClick={handleBad}>
bad
</button>
<h1>statistics</h1>
<p>good {state.good}</p>
<p>neutral {state.neutral}</p>
<p>bad {state.bad}</p>
<p>all {state.tot}</p>
<p>average {state.avg}</p>
<p>positive {state.posPercent} %</p>
</div>
)
}
export default App
In the code below, I've handled the concurrent change of multiple state variables by using a unique global "State", but I don't think it is the best way to do so.
Can anybody suggest me how to change multiple states without keeping them together as I did?
Here's the working code with the "complex state"
import { useState } from 'react'
const App = () => {
const [state, setState] = useState({
good: 0,
neutral: 0,
bad: 0,
tot: 0,
weights: 0,
avg: 0,
posPercent: 0
});
const handleGood = () => {
setState({
...state,
good: state.good +1,
tot: state.tot +1,
weights: (state.good+1)*1 + state.neutral*0 + state.bad*(-1),
avg: ((state.good+1)*1 + state.neutral*0 + state.bad*(-1))/(state.tot +1),
posPercent: ((state.good+1)*100)/(state.tot+1)
});
}
const handleNeutral = () => {
setState({
...state,
neutral: state.neutral +1,
tot: state.tot +1,
weights: state.good*1 + (state.neutral+1)*0 + state.bad*(-1),
avg: (state.good*1 + (state.neutral+1)*0 + state.bad*(-1))/(state.tot +1),
posPercent: ((state.good)*100)/(state.tot+1)
});
}
const handleBad = () => {
setState({
...state,
bad: state.bad +1,
tot: state.tot +1,
weights: state.good*1 + state.neutral*0 + (state.bad+1)*(-1),
avg: (state.good*1 + state.neutral*0 + (state.bad+1)*(-1))/(state.tot +1),
posPercent: ((state.good)*100)/(state.tot+1)
});
}
return (
<div>
<h1>give feedback</h1>
<button onClick={handleGood}>
good
</button>
<button onClick={handleNeutral}>
neutral
</button>
<button onClick={handleBad}>
bad
</button>
<h1>statistics</h1>
<p>good {state.good}</p>
<p>neutral {state.neutral}</p>
<p>bad {state.bad}</p>
<p>all {state.tot}</p>
<p>average {state.avg}</p>
<p>positive {state.posPercent} %</p>
</div>
)
}
export default App
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
useMemo
,请我在这里看到的最大问题(查看您的第二段代码)是,您正在手动尝试更新计算的值(即,
posPercent
,avg
,tot
)这当然是可行的,但它比您可能想要的要麻烦得多。
useMemo
每当给定之一时重新计算一个值依赖关系更改:对所有三个计算值都进行此更改后,您只需负责更新良好、中立和不良计数。
功能更新
请注意如何使用
功能更新
使您的处理程序非常精简:这只是一种风格选择,
setGood(good + 1)
也可以工作。我喜欢它,因为increment
非常易于阅读。和一些数学
,老实说,我没有更深入地了解你想要计算的内容。
neutral*0
不过看起来有点多余。如果我的数学没有让我失败,你可以把它忽略掉。useMemo
, pleaseThe biggest issue I see here (looking at your 2nd piece of code), is that you're manually trying to update values that are calculated (namely,
posPercent
,avg
,tot
)That's certainly doable, but it's a lot more headache than you probably want.
useMemo
re-calculates a value whenever one of the given dependencies changes:With this in place for all three calculated values, you're only responsible for updating the good, neutral, bad counts.
Functional updates
Note how you can use
functional updates
to make your handlers very streamlined:This is merely a stylistic choice,
setGood(good + 1)
works just as well. I like it becauseincrement
is so nicely readable.and a bit of math
I honestly didn't get any deeper into what you're trying to calculate.
neutral*0
though seems, well, a bit redundant. If my math doesn't fail me here, you could just leave this out.状态不应该被改变,因为这可能会导致错误和奇怪的行为。如果您需要根据当前值更新状态,您可以这样做:
这样您就可以使用以前的状态来设置新状态。
在您的代码中,我认为第二种方法可能更好,每个属性都有单独的状态,如果您希望将其全部放在一个状态中,您可以看看 减速器挂钩。
在您的情况下,
handleGood
函数应该是:如果您使用先前的值来更新状态,则必须传递一个接收先前值并返回新值的函数。
States shouldn't be mutated because that may lead you to bugs and strange behaviours. If you need to update your state based on the current value you can do it like this:
This way you can use your previous state to set a new state.
In your code I think maybe it's better the second approach with individual states for every attribute and if you want it all together in one state you may take a look at reducer hook.
In your case the
handleGood
function shoudl be:If you use the previous value to update state, you must pass a function that receives the previous value and returns the new value.
该解决方案旨在提供一个基于 OP 与 useMemo 结合的堆栈片段答案,并使其更加健壮(如果需要添加新选项,请说“非常好”)或“非常糟糕”)。
代码片段
注意
请使用
整页
查看演示 - 这样更容易。说明
上面的代码片段中有内嵌注释可供参考。
This solution seeks to provide a stack-snippet answer based on the one by OP in conjunction with
useMemo
as well as make it a tad more robust (if one needs to add new options, say "very good" or "very bad").Code Snippet
NOTE
Please use
Full Page
to view the demo - it's easier that way.Explanation
There are inline comments in the above snippet for reference.