From e6967c0374060eb110e83469e1b696c6ffc38855 Mon Sep 17 00:00:00 2001 From: zh-lx <18366276315@163.com> Date: Wed, 10 Nov 2021 20:48:33 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=89:=202.=E9=80=92=E5=BD=92=E6=94=B9?= =?UTF-8?q?=E6=88=90=E8=BF=AD=E4=BB=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mini-react/fiber.js | 90 +++++++++++++++++++++++++++++++++++++ src/mini-react/react-dom.js | 34 +------------- 2 files changed, 91 insertions(+), 33 deletions(-) diff --git a/src/mini-react/fiber.js b/src/mini-react/fiber.js index 7b08e34..bd528ec 100644 --- a/src/mini-react/fiber.js +++ b/src/mini-react/fiber.js @@ -1,3 +1,5 @@ +import { renderDom } from './react-dom'; + let nextUnitOfWork = null; let rootFiber = null; @@ -12,3 +14,91 @@ export function createRoot(element, container) { }; nextUnitOfWork = rootFiber; } + +// 执行当前工作单元并设置下一个要执行的工作单元 +function performUnitOfWork(workInProgress) { + if (!workInProgress.stateNode) { + // 若当前 fiber 没有 stateNode,则根据 fiber 挂载的 element 的属性创建 + workInProgress.stateNode = renderDom(workInProgress.element); + } + if (workInProgress.return && workInProgress.stateNode) { + // 如果 fiber 有父 fiber且有 dom + // 向上寻找能挂载 dom 的节点进行 dom 挂载 + let parentFiber = workInProgress.return; + while (!parentFiber.stateNode) { + parentFiber = parentFiber.return; + } + parentFiber.stateNode.appendChild(workInProgress.stateNode); + } + + let children = workInProgress.element?.props?.children; + + let type = workInProgress.element?.type; + if (typeof type === 'function') { + // 当前 fiber 对应 React 组件时,对其 return 迭代 + if (type.prototype.isReactComponent) { + // 类组件 + const { props, type: Comp } = workInProgress.element; + const component = new Comp(props); + const jsx = component.render(); + children = [jsx]; + } else { + // 函数组件 + const { props, type: Fn } = workInProgress.element; + const jsx = Fn(props); + children = [jsx]; + } + } + + if (children || children === 0) { + // children 存在时,对 children 迭代 + let elements = Array.isArray(children) ? children : [children]; + // 打平列表渲染时二维数组的情况(暂不考虑三维及以上数组的情形) + elements = elements.flat(); + + let index = 0; // 当前遍历的子元素在父节点下的下标 + let prevSibling = null; // 记录上一个兄弟节点 + + while (index < elements.length) { + // 遍历子元素 + const element = elements[index]; + // 创建新的 fiber + const newFiber = { + element, + return: workInProgress, + stateNode: null, + }; + if (index === 0) { + // 如果下标为 0,则将当前fiber设置为父 fiber 的 child + workInProgress.child = newFiber; + } else { + // 否则通过 sibling 作为兄弟 fiber 连接 + prevSibling.sibling = newFiber; + } + prevSibling = newFiber; + index++; + } + } + + // 设置下一个工作单元 + if (workInProgress.child) { + // 如果有子 fiber,则下一个工作单元是子 fiber + nextUnitOfWork = workInProgress.child; + } else { + let nextFiber = workInProgress; + while (nextFiber) { + if (nextFiber.sibling) { + // 没有子 fiber 有兄弟 fiber,则下一个工作单元是兄弟 fiber + nextUnitOfWork = nextFiber.sibling; + return; + } else { + // 子 fiber 和兄弟 fiber 都没有,深度优先遍历返回上一层 + nextFiber = nextFiber.return; + } + } + if (!nextFiber) { + // 若返回最顶层,表示迭代结束,将 nextUnitOfWork 置空 + nextUnitOfWork = null; + } + } +} diff --git a/src/mini-react/react-dom.js b/src/mini-react/react-dom.js index f3244e0..54788fa 100644 --- a/src/mini-react/react-dom.js +++ b/src/mini-react/react-dom.js @@ -5,7 +5,7 @@ function render(element, container) { } // 将 React.Element 渲染为真实 dom -function renderDom(element) { +export function renderDom(element) { let dom = null; // 要返回的 dom if (!element && element !== 0) { @@ -25,16 +25,6 @@ function renderDom(element) { return dom; } - if (Array.isArray(element)) { - // 列表渲染 - dom = document.createDocumentFragment(); - for (let item of element) { - const child = renderDom(item); - dom.appendChild(child); - } - return dom; - } - const { type, props: { children, ...attributes }, @@ -43,33 +33,11 @@ function renderDom(element) { if (typeof type === 'string') { // 常规 dom 节点的渲染 dom = document.createElement(type); - } else if (typeof type === 'function') { - // React组件的渲染 - if (type.prototype.isReactComponent) { - // 类组件 - const { props, type: Comp } = element; - const component = new Comp(props); - const jsx = component.render(); - dom = renderDom(jsx); - } else { - // 函数组件 - const { props, type: Fn } = element; - const jsx = Fn(props); - dom = renderDom(jsx); - } } else { // 其他情况暂不考虑 return null; } - if (children) { - // children 存在,对子节点递归渲染 - const childrenDom = renderDom(children); - if (childrenDom) { - dom.appendChild(childrenDom); - } - } - updateAttributes(dom, attributes); return dom;