v1.0
type Hook = {
oldState: any
state: any
queue: Function[]
}
let hook: Hook = null
function useState_(initState: any) {
/**
* 由于render函数的代码量太大,这里就简单的代替一下
* 真实的render函数干了些什么
* 1, 重新构建fiber树
* 2, 构建完fiber树后对真实的dom进行增删改
*/
const [_, render] = useState({})
/**
* useState第一次执行时走这里
* 也就是组件加载的时候
*/
if (!hook) {
hook = {
state: initState,
queue: [],
oldState: null,
}
}
/**
* 组件渲染时, 执行setState存放的回调函数,得到新的hook.state
* useState第一次执行时,也就是组件加载时,hook.queue为空,什么也不做
*/
hook.queue.forEach(action => {
hook.state = action(hook.oldState)
})
/**
* setState的回调函数什么时候执行:
* setState(callball), setState执行时callback会被存起来
* 组件重新渲染时, callback会执行,修改hoo.state值,得到新的state
*/
const setState = (action: any) => {
hook.oldState = hook.state
hook.queue.push(action)
render({})
}
return [hook.state, setState] as const
}
v2.0
let wipFiber = null;// 正在构建的fiber节点
let hookIndex = null;
function updateFunctionComponent(fiber) {
wipFiber = fiber; // 保存下当前正在处理的fiber,这样做的目的是可以任务中断再开始后可以快速恢复之前的状态
hookIndex = 0; // useState每执行一次, hookIndex+1
wipFiber.hooks = []; // useState每执行一次, wipFiber.hooks.push(hook)
const children = [fiber.type(fiber.props)]; // 如果fiber是函数组件,那就执行type方法,把props传过去,返回值又是一个jsx转createElement
reconcileChildren(fiber, children); // 继续调用协调器来处理父fiber和子fiber之间的关系
}
/**
* 函数是组件每一次都会调用这个hook,然后遍历actions有没有
* 有就一次执行action然后将action的结果赋值给hook的state
* 最后由
*/
function useState(initial) { // 初始值就是函数式组件里面定义的useState,这个也会重定向到这个函数
const oldHook =
wipFiber.alternate &&
wipFiber.alternate.hooks &&
wipFiber.alternate.hooks[hookIndex];
/**
* hook.state 的值由 oldHook 决定
*
* 组件更新因别人而起:
* oldHook.queue = [],
* hook.state === oldHook.state,
* 状态保持不变
* setState未执行
*
* 组件更新因自己而起:
* oldHook.queue不为空,
* hook.state的值由oldHook.queue决定,
* 状态将会发生变化
* setState被执行
*/
const hook = {
state: oldHook ? oldHook.state : initial, // wipFiber的最新值, wipFiber.alternate 存放着 wipFiber 需要的最新值
queue: [],// 用于存放setState的回调函数, 这里存放着正在构建的fiber节点的最新值
};
const actions = oldHook ? oldHook.queue : [];
// action 是 setState 的回调函数
// wipFiber.alternate 存放着 wipFiber 需要的最新值
actions.forEach((action) => {
hook.state = action(hook.state);//????????
});
const setState = (action) => {
hook.queue.push(action); // 把所有的改变都放到队列里
wipRoot = {
dom: currentRoot.dom,
props: currentRoot.props,
/**
* 在每一个 fiber 节点上添加 alternate 属性用于记录旧 fiber 节点
*(上一个 commit 阶段使用的 fiber 节点)的引用。
*/
alternate: currentRoot,
};
nextUnitOfWork = wipRoot;
deletions = [];
};
wipFiber.hooks.push(hook);
hookIndex++;
return [hook.state, setState]; // 把state和setState函数暴露出去
}