为什么 componentDidUpdate 不像 useEffect 那样记录实际结果?



以下记录用户超时点击的示例,首先使用useEffect,其次使用componentDidUpdate:

const UseEffectCounter = () => {
const [count, setCount] = useState(0);
useEffect(() => {
setTimeout(() => {
console.log(`You clicked ${count} times`);
}, 3000);
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
)
}
class ComponentDidUpdateCounter extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
}
}
componentDidUpdate() {
setTimeout(() => {
console.log(`You clicked ${this.state.count} times`);
}, 3000);
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({count: this.state.count + 1})}>+1</button>
</div>
)
}
}

第一个示例在3秒超时后按顺序记录,据我所知,每次调用setCount时,状态都会更新,组件会重新渲染,从而在每次重新渲染时触发useEffect,并记录顺序的count值。

我不完全理解第二个例子:如果componentDidUpdate在每次更新后运行,因此每次setState点击按钮,为什么它不按顺序记录count值,而是记录count的最新计算点击次数?

第一个使用useEffect钩子的代码示例,由于闭包的原因,按顺序记录count的值。setTimeout的回调函数关闭count的值,并且每个回调都记录它关闭的count的值。

第二个代码示例记录count的更新值,因为与功能组件示例不同,没有闭包,并且在类组件中,React将this.state.count更改为始终指向状态的最新值。

p.S:有关更多详细信息,请阅读Dan Abramov的这篇blog post on useEffect hook,他在文章中介绍了similar example并解释了这两个代码示例之间的差异。

因为当超时结束时,this.state.count已经更改。当你开始超时时,这个值没有被锁定,当它熄灭时,你正在查找它。

使用useEffect代码,您将记录一个永远不会更改的本地const。即使组件重新发送,也会导致创建一个不同的本地常量,并且您的超时引用的常量保持不变。

最新更新