手动实现一个useState hook

101 阅读1分钟

// 更新的优先级:1.点击的更新是高于服务请求回来的更新的;2.在dispatch中实现
let workInpreogressHook = null
let isMount = true
const fiber = {
    stateNode: App,
    memoizedState: null // 初始化时,存储链表头
}

function useState(initialState) {
    let hook
    if (isMount) {
        hook = { //单向链表
            memoizedState: initialState,
            next: null,
            queue: {
                pending: null // 保存最后一个update
            }
        }
        if (!fiber.memoizedState) {
            fiber.memoizedState = hook
        } else {
            workInpreogressHook.next = hook
        }
        workInpreogressHook = hook
    } else {
        // 非初始化 指针往后走
        hook = workInpreogressHook
        workInpreogressHook = workInpreogressHook.next
    }
    console.log('luov---workInpreogressHook', workInpreogressHook);
    let baseState = hook.memoizedState;
    // 取到新的值
    if (hook.queue.pending) {
        // 存在待更新
        let firstUpdate = hook.queue.pending.next
        do {
            const action = firstUpdate.action
            if (action instanceof Function) {
                baseState = action(baseState) // 拿到新的state
            } else {
                baseState = action
            }
            firstUpdate = firstUpdate.next
        } while (firstUpdate !== hook.queue.pending.next) // 基于环状链表的设计思想
        hook.queue.pending = null // 更新完后清空
    }
    hook.memoizedState = baseState
    return [baseState, dispatchAction.bind(null, hook.queue)] // 第二个参数为什么是hook.queque
}

function dispatchAction(queue, action) {
    // queue链表指向-环状;action:更新的上下文
    const update = {
        action,
        next: null
    }
    if (queue.pending === null) {
        // u0 -> u0 ->u0
        update.next = update
    } else {
        // u1 -> u0 ->u1
        update.next = queue.pending.next
        queue.pending.next = update
    }
    queue.pending = update
    console.log('luov--queue', queue);
    // 每次dispatch之后都会触发一次更新
    schedule()
}

export function schedule() {
    // 更新调用
    workInpreogressHook = fiber.memoizedState
    const app = fiber.stateNode()
    isMount = false
    return app;
}

function App() {
    const [num, updateNum] = useState(0)
    // const [num1, updateNum1] = useState(2)
    // const [num2, updateNum2] = useState(4)
    console.log('luov-isMount:', isMount);
    console.log('luov-num:', num);

    return {
        onclick() {
            updateNum(num => num + 1)
            updateNum(num => num * 10)
            // updateNum2(100)
        }
    }
}

// 初始化
schedule()