1.简介
useState
=> 让函数组件具有维持状态的能力
useState
这个 Hook
是用来管理 state
的,它可以让函数组件具有维持状态的能力。即在一个函数组件的多次渲染之间,这个 state
是共享的。
2.流程图
模拟useState()
- App.js
let isMount = true; // 区分是Mount还是Update
let workInProgressHook = null; // 当前处理的hooks
// 节点
const fiber = {
stateNode: App, // 保存组件
memoizedState: null, // 保存链表,对应每个hooks组件的数据
};
function useState(initialState) {
debugger;
let hook; // 当前hook
if (isMount) {
// 初始化挂载
// 首次渲染创建hooks
hook = {
memoizedState: initialState, // 缓存当前state的值
next: null, // 下个Hook
queue: {
// 缓存更新的队列
pending: null, // 状态
},
};
if (!fiber.memoizedState) {
fiber.memoizedState = hook; // 如果链表数据不存在,直接赋值
} else {
workInProgressHook.next = hook; // 如果存在,第二次useState()
}
workInProgressHook = hook;
} else {
hook = workInProgressHook;
workInProgressHook = workInProgressHook.next;
}
// todo
let baseState = hook.memoizedState;
if (hook.queue.pending) {
let firstUpdate = hook.queue.pending.next;
// 遍历循环链表
do {
const action = firstUpdate.action;
baseState = action(baseState);
firstUpdate = firstUpdate.next;
} while (firstUpdate !== hook.queue.pending.next);
hook.queue.pending = null; // 清空链表
}
hook.memoizedState = baseState;
return [baseState, dispatchAction.bind(null, hook.queue)];
}
function dispatchAction(queue, action) {
const update = {
action,
next: null, // 最后一个update
};
if (queue.pending === null) {
// 当前hooks没触发更新
update.next = update;
} else {
update.next = queue.pending.next;
queue.pending.next = update;
}
queue.pending = update;
schedule(); // 触发更新
}
// 调度
function schedule() {
workInProgressHook = fiber.memoizedState; // 链表指针复位
const app = fiber.stateNode(); // 执行调度
isMount = false;
return app;
}
function App() {
const [num, updateNum] = useState(0);
const [num1, updateNum1] = useState(10);
// const [num1, updateNum1] = useState(0);
console.log("isMount?", isMount);
console.log("num:", num);
console.log("num1:", num1);
return {
onClick() {
// updateNum(num + 1);
updateNum((num) => num + 1);
},
onClick1() {
updateNum1((num) => num + 10);
},
};
}
window.app = schedule();
// 模拟执行点击更新
// app.onClick();
// app.onClick1();
...