为了理解hooks原理,我们遵循React运行流程,实现一个最简useState hook。
考虑如下例子:
function App() {
const [num1, updateNum1] = useState(1);
const [num2, updateNum2] = useState(2);
const [num3, updateNum3] = useState(3);
return (
<p
onClick={() => {
updateNum1((num) => num + 1);
updateNum1((num) => num + 2);
updateNum1((num) => num + 3);
updateNum2((num) => num + 1);
updateNum2((num) => num + 2);
}}
>
{num1},{num2},{num3}
</p>
);
}
ClassComponent是有实例的而FunctionComponent是没有实例的,FunctionCompoent的状态保存在fiber
结构中。每个FunctionComponent对应一个fiber
,结构如下:
fiber = { stateNode: App };
FunctionComponent的状态信息也保存在fiber中,并且以单链表的形式串联在一起,比如例子中mount后的state信息:
fiber = {
stateNode: App,
memoizedState: {
memoizedState: 1,
next: {
memoizedState: 2,
next: {
memoizedState: 3,
next: null,
},
},
},
};
即num1 -> num2 -> num3
。
当点击p标签触发状态更新。每个state都维护一个更新队列,调用更新方法会把更新信息保存到相应的队列中,当所有的更新方法执行完才会触发更新。点击p标签后触发渲染前fiber结构如下:
fiber = {
memoizedState: {
memoizedState: 1,
queue: {
pending: {
action: (num) => num + 1,
next: {
action: (num) => num + 2,
next: {
action: (num) => num + 3,
next: ...,//指向第一个update形成循环链表
},
},
},
},
next: {
memoizedState: 2,
queue: {
pending: {
action: (num) => num + 1,
next: {
action: (num) => num + 2,
next: ...,//指向第一个update形成循环链表
},
},
},
next: {
memoizedState: 3,
queue: {
pending: null,
},
next: null,
},
},
},
};
num1对应的更新循环链表结构:update1 -> update2 -> update3 -> update1
,num2对应的更新循环链表结构:update1 -> update2 -> update1
,num3对应的更新循环链表结构:null
。
当所有更新信息都准备好,React会触发重新渲染,useState方法根据上次状态和对应更新链表信息计算最新的state。