1、存在问题

这里还存在一个问题,就是每次处理一个元素,都要向DOM添加一个新的节点,在完成整个树的渲染之前,由于做了可中断操作,那将看到一个不完整的UI,这样显然是不行的。

2、处理步骤

1.删除子节点添加到父节点的逻辑;

  1. function performUnitOfWork(fiber) {
  2. // 这段逻辑删了
  3. if (fiber.parent) {
  4. fiber.parent.dom.appendChild(fiber.dom)
  5. }
  6. }

2.添加fiber根节点wipRoot,并设置为下一个工作单元;

  1. let wipRoot = null
  2. export function render(element, container) {
  3. // 将根节点设置为第一个工作单元
  4. wipRoot = {
  5. dom: container,
  6. props: {
  7. children: [element],
  8. },
  9. }
  10. nextUnitOfWork = wipRoot
  11. }

3.当完成了所有任务,也就是说没有下一个工作单元了,这时需要把整个fiber渲染为DOM;

  1. // 提交任务,将fiber tree 渲染为真实 DOM
  2. function commitRoot(){
  3. }
  4. function workLoop(deadline) {
  5. // 省略
  6. // 没有下一个工作单元,提交当前fiber树
  7. if (!nextUnitOfWork && wipRoot) {
  8. commitRoot()
  9. }
  10. // 省略
  11. }

4.在 commitRoot 函数中执行提交工作,递归将所有节点附加到 dom 中;

  1. /**
  2. * 处理提交的fiber树
  3. * @param {*} fiber
  4. * @returns
  5. */
  6. function commitWork(fiber){
  7. if (!fiber) {
  8. return
  9. }
  10. const domParent = fiber.parent.dom
  11. // 将自己点添加到父节点下
  12. domParent.appendChild(fiber.dom)
  13. // 渲染子节点
  14. commitWork(fiber.child)
  15. // 渲染兄弟节点
  16. commitWork(fiber.sibling)
  17. }
  18. /**
  19. * 提交任务,将fiber tree 渲染为真实 DOM
  20. */
  21. function commitRoot(){
  22. commitWork(wipRoot.child)
  23. wipRoot = null
  24. }

3、运行结果

运行结果没有问题
image.png

4、本节代码

代码地址:https://github.com/linhexs/mini-react/tree/5.RenderAndCommit