简介
上篇文章主要一步一步的实现了useState,这篇主要是讲解调试useState和useState全部代码
代码
//react中的虚拟dom就是叫fiber
const fiber = {
node: App,
memoizedState: null,
}
//React是双缓存设计,一个是更新工作时使用的fiber,另外一个是负责渲染展示的fiber
let workInprogressFiber = null
//判断是不是初次渲染
let isMount = true
//调度React更新的函数,主要是更新node节点
function schedule() {
workInprogressFiber = fiber.memoizedState
//这里就触发了node节点的更新
const app = fiber.node()
isMount = false
return app
}
//useState的第二个返回值
function setState(queue, action) {
//这里的action可以是函数也可以是值
const update = {
action: action,
next: null
}
if (!queue.pendding) {
update.next = update
} else {
update.next = queue.pendding.next
queue.pendding.next = update
}
queue.pendding = update
//模拟开始调度
schedule()
}
function useState(initValue) {
let hooks = null
if (isMount) {
//初次render,
hooks = {
memoizedState: initValue,
queue: {pendding:null},//后面存放dispath(react的第二个函数)
next:null,
}
//判断是不是起始节点
if (fiber.memoizedState) {
//前面已经有了节点,workInprogressFiber指向的是上一次进入useState的hooks地址
//将上一个hooks的指针指向当前hook,这样就能记录我们的每个useState的调用顺序
workInprogressFiber.next = hooks
} else {
//第一次进fiber,fiber还没有任何状态,
fiber.memoizedState = hooks
}
//workInprogressFiber指向下一个指针
workInprogressFiber = hooks
} else {
//在render阶段,我们调度更新的时候会将workInprogressFiber指向fiber.memoizedState,所以更新的时候就可以直接拿到需要的hooks
hooks = workInprogressFiber
//workInprogressFiber指向下面一个hooks下次进入就可以直接使用
workInprogressFiber = workInprogressFiber.next
}
let baseState = hooks.memoizedState
if (hooks?.queue.pendding) {
//遍历queue,执行完所以的setState
let firstNode = hooks?.queue.pendding.next
do {
const action = firstNode.action
baseState = typeof action === 'function' ? action(baseState) : baseState
firstNode = firstNode.next
}
while (firstNode !== hooks?.queue.pendding.next)
//清空queue
hooks.queue.pendding = null
}
hooks.memoizedState = baseState
//使用bind函数将hooks.queue传入,后面就不必在传hooks.queue
return [baseState, setState.bind(null, hooks.queue)]
}
function App() {
const [num, SetNum] = useState(0)
const [num1, SetNum1] = useState(0)
console.log(fiber)
console.log("num", num)
console.log("num1", num1)
return {
onClick: () => {
SetNum(val => val + 1)
},
add10: () => {
SetNum1(val => val + 10)
}
}
}
window.app = schedule()