// React Hooks模拟
// 用于保存组件是update还是mount
let isMount = true;
// 保存我们当前正在处理的hook
let workInProgressHook = null;
// React 中每一个组件对应一个fiber节点
const fiber = {
// 保存组件本身
stateNode: App,
// 对于函数式组件,保存的是hooks的链表,对于类组件保存的是state
// 问: Hooks信息为什么要使用链表存储而不是数组
memoizedState: null,
}
// 用于调度组件执行
function schedule() {
// 每次执行组件的时候,需要将workInProgressHook复位,重新指向第一个hook
workInProgressHook = fiber.memoizedState;
const app = fiber.stateNode();
isMount = false;
return app;
}
/**
* useState实现
*/
function useState(initialState) {
let hook;
if (isMount) {
// 首次渲染的时候需要初始化一个hook
hook = {
// hook上的memoizedState保存的是hook的状态
memoizedState: initialState,
// 指向下一个hook
next: null,
// 保存hook的更新信息 比如 setNum(n => n+1)中的n => n+1函数,为什么事一个队列,因为我们可以在一次操作中调用多次setNum(n => n+1)函数
// 比如说在onClick事件中
queue: {
pending: null
}
}
// 表示是第一个hook
// 这就是为什么我们执行多个useState他们之间可以相互对应的原因
if (!fiber.memoizedState) {
fiber.memoizedState = hook;
} else {
workInProgressHook.next = hook;
}
workInProgressHook = hook; // 指针继续向下移动
} else {
// 表示已经有了一条链表
// 此时workInProgressHook指向这个链表的正在执行的hook
// 获取到我们当前要执行的hook
hook = workInProgressHook;
workInProgressHook = workInProgressHook.next;
}
console.log(hook)
// 找到计算state依据的基础的state
let baseState = hook.memoizedState;
// 说明本次的状态改变有update要执行
if (hook.queue.pending) {
let firstUpdate = hook.queue.pending.next;
// 遍历链表
do {
const action = firstUpdate.action; // setState传入的值这里是函数
// 更新基础的state
baseState = action(baseState);
firstUpdate = firstUpdate.next;
} while (firstUpdate !== hook.queue.pending.next)
// 状态计算完成之后需要将hook.queue.pending = null
hook.queue.pending = null;
}
hook.memoizedState = baseState;
return [baseState, dispatchAction.bind(null, hook.queue)]
}
// state的update函数在React中有自己的名字,叫dispatchAction
function dispatchAction(queue, action) {
// 那么我们如何知道dispatchAction是来更新哪一个state呢?
// 创建一个数据结构,这个数据结构就记录着一次更新, 也是一个链表的形式
// hook的链表是一个单向链表,但是update的链表却是一个环形链表。因为React中的update是有优先级的
const update = {
action,
next: null
}
// 说明当前hook上还有要触发的更新,说明这个update是我们要触发的第一次更新
if (queue.pending === null) {
update.next = update;
} else {
// 不是第一次更新
// queue.pending保存的是hook的最后一个update
// queue.pending.next则就是这个环的第一个update,所以queue.pending也是一个环形链表
update.next = queue.pending.next;
queue.pending.next = update;
}
// 移动指针
queue.pending = update;
// 组件执行
schedule();
}
function App() {
const [num, setNum] = useState(0);
const [num1, setNum1] = useState(10);
console.log(isMount);
console.log(num);
console.log(num1);
return {
onClick() {
setNum(n => n + 1)
},
onFocus() {
setNum1(n => n + 10)
}
}
}
window.app = schedule();
网友评论