热身准备
在正式讲useState
,我们先热热身,了解下必备知识。
为什么会有hooks
大家都知道hooks
是在函数组件的产物。之前class
组件为什么没有出现hooks
这种东西呢?
答案很简单,不需要。
因为在class
组件中,在运行时,只会生成一个实例,而在这个实例中会保存组件的state
等信息。在后续的更新操作中,也只是调用其中的render
方法,实例中的信息不会丢失。而在函数组件中,每次渲染,更新都会去执行这个函数组件,所以在函数组件中是没办法保存state
等信息的。为了保存state
等信息,于是有了hooks
,用来记录函数组件的状态,执行副作用。
hooks执行时机
上面提到,在函数组件中,每次渲染,更新都会去执行这个函数组件。所以我们在函数组件内部声明的hooks
也会在每次执行函数组件时执行。
在这个时候,可能有的同学听了我上面的说法(hooks
用来记录函数组件的状态,执行副作用),又有疑惑了,既然每次函数组件执行都会执行hooks
方法,那hooks
是怎么记录函数组件的状态的呢?
答案是,记录在函数组件对应的fiber
节点中。
相关参考视频讲解:进入学习
两套hooks
在我们刚开始学习使用hooks
时,可能会有疑惑, 为什么hooks
要在函数组件的顶部声明,而不能在条件语句或内部函数中声明?
答案是,React
维护了两套hooks
,一套用来在项目初始化mount
时,初始化hooks
。而在后续的更新操作中会基于初始化的hooks
执行更新操作。如果我们在条件语句或函数中声明hooks
,有可能在项目初始化时不会声明,这样就会导致在后面的更新操作中出问题。
hooks存储
提前讲一下hooks存储方式,避免看晕了~~~
每个初始化的hook
都会创建一个hook
结构,多个hook
是通过声明顺序用链表的结构相关联,最终这个链表会存放在fiber.memoizedState
中:
var hook = {
memoizedState: null, // 存储hook操作,不要和fiber.memoizedState搞混了
baseState: null,
baseQueue: null,
queue: null, // 存储该hook本次更新阶段的所有更新操作
next: null // 链接下一个hook
};
而在每个hook.queue
中存放的么个update
也是一个链表结构存储的,千万不要和hook
的链表搞混了。
接下来,让我们带着下面几个问题看文章:
- 为什么
setState
后不能马上拿到最新的state
的值? - 多个
setState
是如何合并的? setState
到底是同步还是异步的?- 为什么
setState
的值相同时,函数组件不更新?
假如我们有下面这样一段代码:
function App(){
const [count, setCount] = useState(0)
const handleClick