React的hook之useState简单实现

hook状态在哪保存

函数组件的fiber上,有着memorizedState属性,并且以{ memorizedState: null, next: null }的链表形式保存着每一个hook函数状态。

形如:

fiber = {
    memorizedState: {
        memorizedState: value,
        next: {
            memorizedState: value,
            next: null
        }
    }
}

首次渲染和更新时的状态处理准备

fiber的alternate属性保存着上次渲染fiber

function scheduleUpdateOnFiber(fiberRoot) {
    fiberRoot.alternate = { ...fiberRoot }
    wipRoot = fiberRoot
    nextUnitOfWork = fiberRoot
    scheduleCallback(workLoop);
}

渲染到函数组件时,renderHook函数获取当前的函数fiber,初始化本轮渲染的属性

// 函数组件首次渲染或更新
function updateFnFiber(fiber) {
    renderHooks(fiber);
    const { type, props } = fiber;
    let children = type(props);
    reconcileChildren(fiber, children);
}

初始化本轮渲染的属性

// 调用当前hook函数的函数fiber
let currentlyRenderingFiber = null;
// 尾hook节点
let workInProgressHook = null;

function renderHooks(wip) {
    currentlyRenderingFiber = wip;
    currentlyRenderingFiber.memorizedState = null; 
    workInProgressHook = null;
}

useState方法实现

react组件函数的执行会调用useState

export function useState(initialState) {
    // 获取到当前 useState对应的hook链表节点
    const hook = updateWorkProgressHook();

    if (!currentlyRenderingFiber.alternate) {
        // 若是初次渲染节点,保存初始值
        hook.memorizedState = initialState;
    }
    //  dispatch方法因为闭包,引用着对应的hook,修改了hook状态值,开始新一轮更新。
    //
    const dispatch = (state) => {
        hook.memorizedState = state;
        //从函数组件开始往下协调更新
        scheduleUpdateOnFiber(currentlyRenderingFiber);
    };

    return [hook.memorizedState, dispatch];
}

updateWorkProgressHook函数

updateWorkProgressHook函数处理和获取当前hook对应状态

//获取当前hook , 也是构建fibe上hook链表的过程
function updateWorkProgressHook() {
    let hook = null;
    //  第一次渲染时函数fiber上没有alternate
    //  更新时alternate上存在最新的hook状态
    const current = currentlyRenderingFiber.alternate;
    if (current) {
        // 更新
        // fiber的memorizedState指向新一轮的hook链表
        currentlyRenderingFiber.memorizedState = current.memorizedState;
        if (workInProgressHook) {
            //有尾hook节点,新的hook为尾hook节点的下一个
            hook = workInProgressHook = workInProgressHook.next;
        } else {
           //没尾hook节点,获取第一个hook节点,current.memorizedState指向第一个节点
            hook = workInProgressHook = current.memorizedState;
        }
    } else {
        // 初次渲染,返回空hook
        hook = { memorizedState: null, next: null };
        currentHook = null;
        if (workInProgressHook) {
            //有尾hook节点,新的hook加入链表末尾
            workInProgressHook = workInProgressHook.next = hook;
        } else {
            //没有尾hook节点,新的hook为hook链表开端
            workInProgressHook = currentlyRenderingFiber.memorizedState = hook;
        }
    }

    return hook;
}

useReducer方法实现

和useState类似,只是dispatch方法里,每次新的值是用reducer函数的返回

export function useReducer(reducer, initialState) {
    const hook = updateWorkProgressHook();

    if (!currentlyRenderingFiber.alternate) {
        hook.memorizedState = initialState;
    }
    //  定义一个dispatch,调用时执行reducer方法获取计算后的状态值
    const dispatch = (action) => {
        hook.memorizedState = reducer(hook.memorizedState, action);
        scheduleUpdateOnFiber(currentlyRenderingFiber);
    };

    return [hook.memorizedState, dispatch];
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容