我对 React 还很陌生,并试图围绕钩子来包扎我的头。 我现在正在搞砸一个非常简单的反例,使用 console.log(( 来尝试了解幕后发生的事情:
import React, { useState, useEffect } from 'react'
const Counter = () => {
const [ count, updateCount ] = useState(0)
console.log(count)
useEffect(() => {
updateCount(10)
console.log(count)
}, [count])
return (
<div>
<h1>Counter</h1>
<div>
<button onClick={() => updateCount(count-1)}>-</button>
<span>{count}</span>
<button onClick={() => updateCount(count+1)}>+</button>
</div>
</div>
)
}
当我加载此页面时,我看到 0、0、10、10、10 记录到控制台。 据我了解,这就是正在发生的事情:
- 呈现组件,将默认值
count
设置为 0。 - 然后按照第 5 行将 0 记录到控制台
useEffect
总是在组件首次呈现时执行,而不考虑其依赖项(对吗?(,因此它会执行updateCount(10)
- 在状态从
updateCount(10)
实际更新之前,0 按照第 9 行记录到控制台 count
更新,因为updateCount(10)
. 由于状态已更改,因此组件将重新呈现。按照第 5 行再次将 10 记录到控制台- 由于
count
被列为useEffect
的依赖项,并且count
已更改,因此useEffect
再次执行。 - 再次调用
updateCount(10)
,尽管它不应该执行任何操作,因为count
已经是 10
。 - 10 再次记录到控制台,如第 9 行所示。
- 这样,从第 5 行开始,还有 10 个记录到控制台。 我很困惑为什么再次执行。 上次调用
useEffect
时,它再次将count
设置为 10,但由于count
已经设置为 10,组件应该不需要重新渲染,那么为什么再次执行第 5 行呢? 或者每次更新时都会重新渲染组件 状态被调用,无论状态的属性是否实际更改?
您看到第三个 10 个注销的原因是因为并发的反应实现细节中的一个怪癖。
https://github.com/facebook/react/issues/17474
通常,如果 setState 严格相等,则组件不会重新渲染:updateCount(prevState => prevState)
但是,如果状态值有任何歧义(由于并发性(,react 需要做一个"第二个"渲染,以确保状态值是相同的。
这绝对是一个有趣的怪癖,并表明您永远不应该依赖组件渲染的次数。