一、源代码
逻辑十分绕,建议多敲几遍。
let isMount = true; // 判断是挂载还是更新
let workInProgressHook;
// App组件对应的fiber对象
const fiber = {
memorizedState: null, // 当前hook的相关信息
stateNode: App
}
function schedule() {
// 更新前将workInProgressHook重置为fiber保存的第一个Hook
workInProgressHook = fiber.memorizedState;
const app = fiber.stateNode();
isMount = false;
return app; // 方便调试 触发事件
}
/**
* 调用setState方法,相当于调用这个方法,从而实现state状态更新
* @param {*} queue
* @param {*} action
*/
function dispatchAction(queue, action) {
const update = {
action,
next: null
}
// 环状链表
if (queue.pending === null) {
update.next = update;
} else {
update.next = queue.pending.next;
queue.pending.next = update;
}
queue.pending = update;
// 开始调度
schedule();
}
// 手写hook
function useState (initalState) {
let hook;
// 最开始刚挂载的时候
if (isMount) {
hook = {
queue: {
pending: null
},
memorizedState: initalState,
next: null
}
// 初始化时候 只调用一次 setState的情况
if (!fiber.memorizedState) {
fiber.memorizedState = hook;
// 初始化的时候 有多个useState的情况
} else {
// 不断追加到链表后面
workInProgressHook.next = hook;
}
workInProgressHook = hook;
}
// 执行update操作的时候
else {
hook = workInProgressHook;
workInProgressHook = workInProgressHook.next;
}
let baseState = hook.memorizedState;
if (hook.queue.pending) {
let firstUpdate = hook.queue.pending.next;
do {
const {action} = firstUpdate;
baseState = action(baseState);
firstUpdate = firstUpdate.next;
} while(firstUpdate !== hook.queue.pending)
hook.queue.pending = null;
}
hook.memorizedState = baseState;
return [baseState, dispatchAction.bind(null, hook.queue)]
}
// 组件
function App() {
const [state, setState] = useState(0);
const [state2, setState2] = useState(1);
console.log('workInProgressHook', workInProgressHook, state, state2)
return {
click () {
setState(state => state + 1);
setState(state => state + 1);
},
focus () {
setState2(state2 => state2 + 1)
}
}
}
window.app = schedule();