xdm,又要到饭了,又更新代码了!
总结一下上一篇完成的内容,
- 改进了useState的实现, 可以配合fiber进行渲染。
有兴趣的可以点这里查看重构useState的实现 (1)
useState的实现还没有完美,即现在每次的调用setState 都会重新渲染。这不是我们想要的,我们想要的多次更新merge只更新最新的那次数据,不是现在的每次都会单独更新一次。
添加一个批量更新是一个非常简单的,基于js单线程的特质,可以添加一个锁机制来完成。 使用setState,会调用 requestHostCallback ,这个函数会绘制fiber树,接着根据更新好的fiber树,进行ui的更新。那么这个函数里面添加一个锁,即只有当前的锁===false, 才更新fiber/ui。
用户即使一个事件循环内多次调用setState也只会有一次fiber/ui 的更新。但是setState会收集所有的更新逻辑。因为setState 的更新默认属于异步,所以真正更新fiber/ui和批量添加更新逻辑不在一个循环。这是现在的useState代码,
function useState(initial) {
// workInProgress , 当前fiber
const oldHook = workInProgress.alternate && workInProgress.alternate.hooks && workInProgress.alternate.hooks[workInProgress.currentHook]
const hook = {
state: oldHook.state || initial
queue: []
}
const actions = oldHook ? oldHook.queue : []
actions.forEach(action => {
hook.state = typeof action === 'function' ? action(hook.state) : action
})
if (oldHook)
oldHook.queue = []
const setState = action => {
if (typeof action === 'function') {
hook.queue.push(prevState=>action(prevState))
} else hook.queue.push(action)
requestHostCallback(workLoop)
}
workInProgress.hooks.push(hook)
workInProgress.currentHook++
return [hook.state, setState]
}
上面的代码每次调用setState都会调用requestHostCallback(workLoop) 函数进行 fiber / ui 的更新,那么添加锁的位置就是在 requestHostCallback 函数里面。
// 工作循环
let workLoopScheduled = false;
function requestHostCallback(callback) {
if (workLoopScheduled) return;
// 已经调度,直接返回
workLoopScheduled = true;
// 标记为已调度
if (typeof requestIdleCallback !== 'undefined') {
requestIdleCallback(deadline => {
workLoopScheduled = false;
// 渲染循环开始时重置标志
callback(deadline);
});
} else {
// 浏览器不支持 requestIdleCallback 时的回退方案
setTimeout(() => {
workLoopScheduled = false;
// 渲染循环开始时重置标志
callback({ timeRemaining: () => Infinity }); }, 0);
}
}
function workLoop(deadline) {
while (nextUnitOfWork && deadline.timeRemaining() > 0) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
if (nextUnitOfWork) {
requestHostCallback(workLoop);
}
else {
commitRoot();
}
workLoopScheduled = false;
}
这样就利用了锁机制以及js单线程实现了useState批量更新的机制。
这一章节实现了useState函数批量更新实现。
下一篇将开始重构之前的useEffect hook
如果这样的长度/强度你觉得可以接受,觉得有帮助,可以继续阅读下一篇,实现一个 Mini React:核心功能详解 - 重构useEffect的实现 。
如果文章对你有帮助,请点个赞支持一下!
啥也不是,散会。