实现useState调试加全代码

66 阅读2分钟
简介

上篇文章主要一步一步的实现了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()
调试

image.png