[英]Consequences of using computed variables vs useState/useEffect
If I have a variable whose value can be fully derived based on the value of another property, is there any consequence/pitfall to initializing a computed variable vs using a combination of useState
/ useEffect
to track the variable?如果我有一个变量的值可以完全基于另一个属性的值导出,那么初始化计算变量与使用
useState
/ useEffect
的组合来跟踪变量是否有任何后果/陷阱? Let me illustrate with a contrived example:让我用一个人为的例子来说明:
/**
* ex paymentAmounts: [100, 300, 400]
*/
const Option1 = ({paymentAmounts}) => {
const [average, setAverage] = useState(paymentAmounts.reduce((acc, curr) => curr + acc, 0) / paymentAmounts.length)
useEffect(() => {
setAverage(paymentAmounts.reduce((acc, curr) => curr + acc, 0) / paymentAmounts.length)
}, [paymentAmounts])
return (
<div>
Average: {average}
</div>
)
}
or more simply或更简单地说
/**
* ex paymentAmounts: [100, 300, 400]
*/
const Option2 = ({paymentAmounts}) => {
const average = paymentAmounts.reduce((acc, curr) => curr + acc, 0) / paymentAmounts.length
return (
<div>
Average: {average}
</div>
)
}
Am I giving up any control and/or React benefits by using Option2?我是否通过使用 Option2 放弃了任何控制和/或 React 好处?
Vue.js seems to have this option viacomputed properties . Vue.js 似乎通过计算属性有这个选项。
The only reason to use hooks or other state tracking functionality is if you plan on changing the state within the component itself.使用钩子或其他状态跟踪功能的唯一原因是如果您计划更改组件本身的状态。 From the example you gave, that is not the case.
从你给出的例子来看,情况并非如此。 If the prop
paymentAmounts
is updated the component will get updated by React and so will your computed constant, average
.如果 prop
paymentAmounts
更新,组件将被 React 更新,你的计算常量average
也会更新。
So, you get no benefit from using useState & useEffect here.因此,在这里使用 useState 和 useEffect 没有任何好处。 Keep it simple with your computed constant!
用你的计算常数保持简单!
You use state (as in useState
that is) when you want to track something in your component (or share it between its children) between rerenders .当您想在 rerenders之间跟踪组件中的某些内容(或在其子组件之间共享)时,您可以使用 state(如
useState
中的)。 In your case, you're getting this "state" from your parent component (the parent is the actual state holder).在您的情况下,您从父组件(父组件是实际的状态持有者)获取此“状态”。 Every change in the parent state (
paymentAmounts
in your situation) will reflect in your child component automatically.父状态的每次更改(您的情况下的
paymentAmounts
)都会自动反映在您的子组件中。
As a general "rule", don't use state for data that can be calculated.作为一般“规则”,不要将状态用于可计算的数据。 Keep in mind that every change of a state tracked variable will force the component to re-render.
请记住,状态跟踪变量的每次更改都会强制组件重新渲染。 Another bad usage example is this:
另一个不好的用法示例是:
const Example = ({variable1}) => {
const [variable, setVariable] = useState(variable1);
...
}
A couple of additional notes:一些附加说明:
useEffect
.useEffect
引入了额外的开销。 As pointed out already, your child component will always re-render and recalculate the average
when your parent's state change.average
。setAverage
wrong in your useEffect
hook.setAverage
挂钩中使用了错误的useEffect
。 The setter takes either a new value or a function that accepts the current one and returns the new one. paymentAmounts / paymentAmounts.length
calculation.paymentAmounts / paymentAmounts.length
计算的期望。 I suppose it is just a dummy code, but if not, look into it. So, in short - Yes, you should be using a simple variable to calculate the average and ditch the useState
/ useEffect
.因此,简而言之 - 是的,您应该使用一个简单的变量来计算平均值并
useState
/ useEffect
。 Not only you're NOT giving up any benefits, you're actually making your code more performant, maintainable, readable and error-free.您不仅没有放弃任何好处,而且实际上使您的代码更具性能、可维护性、可读性和无错误。
Let's analyze the Option1
component step-by-step:让我们一步一步分析
Option1
组件:
/**
* ex paymentAmounts: [100, 300, 400]
*/
const Option1 = ({paymentAmounts}) => {
//1
const [average, setAverage] = useState(paymentAmounts / paymentAmounts.length)
//2
useEffect(() => {
setAverage(paymentAmounts.reduce((acc, curr) => curr + acc, 0) / paymentAmounts.length)
}, [ paymentAmounts])
return (
<div>
Average: {average}
</div>
)
}
average
state variable from the paymentAmounts
prop.paymentAmounts
初始化average
状态变量。 During the initial render, the initial value of the average
state variable would be calculated from it.average
状态变量的初始值。 So far so good.useEffect
you are adding a dependency on the paymentAmounts
array from the prop.useEffect
中,您正在从 prop 添加对paymentAmounts
数组的依赖项。 The effect callback will run when a new array instance is passed as a prop and also on the initial render.average
if you simply do paymentAmounts.push(400)
in Option1
's parent component.Option1
的父组件中执行paymentAmounts.push(400)
,您可能会看到average
没有变化。 So for all use cases Option2
is the best way to achieve what you wanted to do.因此,对于所有用例,
Option2
是实现您想要做的事情的最佳方式。 There is no need to introduce a state in this functional component.无需在此功能组件中引入状态。 The value in the UI can be derived from the
props
itself. UI 中的值可以来源于
props
本身。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.