假设我有一个依赖于其他状态的状态(例如,当A改变时,我希望B改变)。
在useEffect钩子中创建一个观察A并设置B的钩子是否合适?
当我点击按钮的时候,效果会级联吗,第一个效果会触发,导致b改变,导致第二个效果在下一次渲染之前触发?像这样构造代码有性能上的缺点吗?
let MyComponent = props => {
let [a, setA] = useState(1)
let [b, setB] = useState(2)
useEffect(
() => {
if (/*some stuff is true*/) {
setB(3)
}
},
[a],
)
useEffect(
() => {
// do some stuff
},
[b],
)
return (
<button
onClick={() => {
setA(5)
}}
>
click me
</button>
)
}
6条答案
按热度按时间q3qa4bjr1#
一般来说,在
useEffect
中使用setState
将创建一个无限循环,这很可能是您不希望造成的。对于该规则,有几个例外,我将在后面介绍。useEffect
在每次渲染之后被调用,并且当setState
在其内部被使用时,它将导致组件重新渲染,这将调用useEffect
等等。在
useEffect
中使用useState
不会导致无限循环的一个常见情况是,当您将一个空数组作为第二个参数传递给useEffect
(如useEffect(() => {....}, [])
)时,这意味着effect函数应该被调用一次:当你在一个组件中进行数据获取,并且你想要在组件的状态中保存请求数据时,这被广泛使用。li9yvcax2#
为了将来的目的,这也可能有所帮助:
在
useEffect
中使用setState是可以的,您只需要注意前面描述的不要创建循环。但这不是唯一可能发生的问题。请参见以下内容:
假设您有一个组件
Comp
,它从父组件接收props
,并且根据props
的更改,您希望设置Comp
的状态。由于某些原因,您需要更改不同useEffect
中的每个属性:不要这样做
它可能永远不会更改的状态,如您在此示例中所见:https://codesandbox.io/s/confident-lederberg-dtx7w
在本例中发生这种情况的原因是,当您同时更改
prop.a
和prop.b
时,两个useEffects在同一个React周期中运行,因此,当您执行setState
时,{...state}
的值在两个useEffect
中完全相同,因为它们处于相同的上下文中。当您运行第二个setState
时,它将替换第一个setState
。改做这个
这个问题的解决方案基本上是这样调用
setState
:在此查看解决方案:https://codesandbox.io/s/mutable-surf-nynlx
现在,当您继续使用
setState
时,您总是会收到状态的最新且正确的值。6xfqseft3#
效果总是在渲染阶段完成后执行,即使您在一个效果中设置了状态,另一个效果也将读取更新的状态,并仅在渲染阶段后对其执行操作。
我已经说过,最好以相同的效果执行这两个操作,除非
b
可能由于changing a
以外的原因而更改,在这种情况下,您也希望执行相同的逻辑kdfy810k4#
useEffect
可以在某个属性或状态上挂钩。因此,要避免无限循环挂钩,您需要做的事情是绑定一些变量或状态来实现例如:
上述效果将激发只有一次这组件已rendered.这是类似于
componentDidMount
生命周期以上效果只在我的状态改变时触发,类似于
componentDidUpdate
,但不是每个改变的状态都会触发。您可以通过此链接阅读更多详细信息
ddrv8njm5#
▶ 1.可以在useEffect钩子内设置状态吗?
原则上,您可以在需要的地方自由设置状态-包括在
useEffect
内部,甚至在渲染过程中。只需确保通过正确设置Hookdeps
和/或有条件地设置状态来避免无限循环。▶ 2.假设我有一个状态依赖于另一个状态,在useEffect钩子中创建一个钩子来观察A并设置B合适吗?
您刚才描述了
useReducer
的 * 经典 * 使用情形:当您有涉及多个子值的复杂状态逻辑时,或者当下一个状态依赖于前一个状态时,
useReducer
通常优于useState
。(React docs)当设置一个state变量依赖于另一个state**变量的当前值时,你可能想尝试用
useReducer
来替换它们。[...]当你发现自己在写setSomething(something => ...)
时,是时候考虑使用一个reducer了。▶ 3.效果是否会级联,当我点击按钮时,第一个效果会触发,导致b改变,导致第二个效果在下一次渲染之前触发?
useEffect
始终在提交渲染并应用DOM更改 * 之后 * 运行。第一个效果触发,更改b
并导致重新渲染。此渲染完成后,由于b
更改,第二个效果将运行。一个二个一个一个
▶ 4.这样的代码结构是否会降低性能?
是的。通过将
b
的状态更改 Package 到a
的单独useEffect
中,浏览器具有额外的布局/绘制阶段-这些效果可能对用户可见。如果您不想尝试useReducer
,您可以直接将b
的状态与a
一起更改:gudnpqoy6#
尝试将setState Package 在一个if语句中,该语句检查是否需要更改状态-如果需要,则更改它,否则
return () => {}
例如,