共计 2150 个字符,预计需要花费 6 分钟才能阅读完成。
手写 hooks 最要害的是要了解 hook 队列和 update 队列的指针指向和 updateQueue 的更新计算
import React from "react";
import ReactDOM from "react-dom";
let workInProgressHook;// 当前工作中的 hook
let isMount = true;// 是否时 mount 时
const fiber = {//fiber 节点
memoizedState: null,//hook 链表
stateNode: App//dom
};
const Dispatcher = (() => {//Dispatcher 对象
function mountWorkInProgressHook() {//mount 时调用
const hook = {// 构建 hook
queue: {// 更新队列
pending: null// 未执行的 update 队列
},
memoizedState: null,// 以后 state
next: null// 下一个 hook
};
if (!fiber.memoizedState) {fiber.memoizedState = hook;// 第一个 hook 的话间接赋值给 fiber.memoizedState} else {workInProgressHook.next = hook;// 不是第一个的话就加在上一个 hook 的前面,造成链表}
workInProgressHook = hook;// 记录当前工作的 hook
return workInProgressHook;
}
function updateWorkInProgressHook() {//update 时调用
let curHook = workInProgressHook;
workInProgressHook = workInProgressHook.next;// 下一个 hook
return curHook;
}
function useState(initialState) {
let hook;
if (isMount) {hook = mountWorkInProgressHook();
hook.memoizedState = initialState;// 初始状态
} else {hook = updateWorkInProgressHook();
}
let baseState = hook.memoizedState;// 初始状态
if (hook.queue.pending) {
let firstUpdate = hook.queue.pending.next;// 第一个 update
do {
const action = firstUpdate.action;
baseState = action(baseState);
firstUpdate = firstUpdate.next;// 循环 update 链表
} while (firstUpdate !== hook.queue.pending);// 通过 update 的 action 计算 state
hook.queue.pending = null;// 重置 update 链表
}
hook.memoizedState = baseState;// 赋值新的 state
return [baseState, dispatchAction.bind(null, hook.queue)];//useState 的返回
}
return {useState};
})();
function dispatchAction(queue, action) {// 触发更新
const update = {// 构建 update
action,
next: null
};
if (queue.pending === null) {update.next = update;//update 的环状链表} else {
update.next = queue.pending.next;// 新的 update 的 next 指向前一个 update
queue.pending.next = update;// 前一个 update 的 next 指向新的 update
}
queue.pending = update;// 更新 queue.pending
isMount = false;// 标记 mount 完结
workInProgressHook = fiber.memoizedState;// 更新 workInProgressHook
schedule();// 调度更新}
function App() {let [count, setCount] = Dispatcher.useState(1);
let [age, setAge] = Dispatcher.useState(10);
return (
<>
<p>Clicked {count} times</p>
<button onClick={() => setCount(() => count + 1)}> Add count</button>
<p>Age is {age}</p>
<button onClick={() => setAge(() => age + 1)}> Add age</button>
</>
);
}
function schedule() {ReactDOM.render(<App />, document.querySelector("#root"));
}
schedule();
相干参考视频解说:进入学习
正文完