前言
在使用Hooks时常常会出现一些有趣的问题,这些问题往往跟你之前的Component组件的思维有关。
Hooks与Component
Hooks的useEffect的确可以模拟部分class组件中生命周期的方法,但并不能把两者等同。因为两者本身是不同的(看起来像是一句废话)
Function组件是没有实例的,而Component组件是有实例的,这会导致在Function组件中没有办法引用和保证前一个state,而Component组件是可以的,所以Hooks添加了useRef。
可以再看下两者在渲染时的差异
Function 组件
function Example() {
const [count, setCount] = useState(0);
function handleAlertClick() {
setTimeout(() => {
alert('You clicked on: ' + count);
}, 3000);
}
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
<button onClick={handleAlertClick}>
Show alert
</button>
</div>
);
}
Component组件
class Example extends React.Component{
state={
count:0
}
handleAlertClick=()=> {
setTimeout(() => {
alert('You clicked on: ' + this.state.count);
}, 3000);
}
render(){
const {count}=this.state;
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => this.setState({count:count+1})}>
Click me
</button>
<button onClick={this.handleAlertClick}>
Show alert
</button>
</div>
);
}
}
同样的操作,比如点击Click Me按钮,先点击3次,然后点击Show alert按钮,再点击Click Me按钮2次。
那么同样的操作在两者中的alert结果是不同的:
- Function组件:
alert的是3 - Component组件:
alert的是5
原因在于Function组件的render相当于对当前状态进行了一次快照,props、state和其他事件函数等等都是重新生成的且独立的。这不同于Component组件,Component组件的props、state和事件函数可以保存在实例上,不需要重新生成,也就是实时的。
当然上面的Function组件例子中也有涉及到闭包相关的东西。
Hooks与闭包
Function组件在使用Hooks时会产生闭包。
在查看Hooks源码后也能体现出来。
闭包的其中一个特性是可以保持一个变量的持续引用。
再加上Function组件每次render都是一次独立的快照,即重新生成的了一个全新的函数。
那么当之前的异步函数发生调用时,由于闭包的特性,还保持了对于之前的引用,所以就导致了上述例子Function组件alert出来的是3。
由于Component组件的思维模式,在Hooks的开发中,常常会导致一些问题,其他很大一部分就是由于Function的快照与闭包导致的。
参考:
1.Hook 概览——React官方文档
2.Hooks FAQ——React官方文档
3.简单聊一聊 hooks 与闭包——Limboer
4.a-complete-guide-to-useeffect——Dan Abramov
网友评论