建立你自己的react(六)---Render和 Commit 阶段

85 阅读1分钟

前言

上次我们讲了fiber,我来提一个问题,大家来回顾一下,fiber为什么采用的链式结构?也就是说链式结构有什么特点?

  • 可以被中断
  • 链式结构方便增加和删除

记住这些特点,所以上一课讲的performUnitOfWork函数其实也就是根据条件生成链式结构树,并返回下一个节点

render和Commit阶段

我们还有另一个问题在这里。

if (fiber.parent) {
  fiber.parent.dom.appendChild(fiber.dom)
}

每次处理一个元素时,我们都要向 DOM 添加一个新节点。还有,请记住,浏览器可能会在我们完成渲染整棵树之前中断我们的工作。在这种情况下,用户将看到一个不完整的 UI。我们不想那样。

所以我们需要从这里移除改变DOM的这部分。

替代方案是, 我们将继续保持fiber 树的根节点的追踪。我们称它为正在进行的工作root 或者 wipRoot。

function render(element, container) {
  wipRoot = {
    dom: container,
    props: {
      children: [element],
    },
  };
  nextUnitOfWork = wipRoot;
}

这样我们就能一次完成所有的工作(我们知道这是因为没有下一个工作单元了)我们commit这整个fiber tree到这个DOM

function commitRoot() {
  // TODO add nodes to dom
}

function workLoop(deadline) {
  let shouldYield = false
  while (nextUnitOfWork && !shouldYield) {
    nextUnitOfWork = performUnitOfWork(
      nextUnitOfWork
    )
    shouldYield = deadline.timeRemaining() < 1
  }
​
  if (!nextUnitOfWork && wipRoot) {
    commitRoot()
  }
​
  requestIdleCallback(workLoop)
}

我们在commitRoot函数中执行它。 这里我们递归的添加所有的node到DOM上

function commitRoot() {
  commitWork(wipRoot.child)
  wipRoot = null
}
​
function commitWork(fiber) {
  if (!fiber) {
    return
  }
  const domParent = fiber.parent.dom
  domParent.appendChild(fiber.dom)
  commitWork(fiber.child)
  commitWork(fiber.sibling)
}

这里的commitRoot函数,你看这不就是采用的遍历树的算法么,所以学好算法很重要,如果你想成为一代大师的话

参考