Skip to content

Commit

Permalink
三: 2.递归改成迭代
Browse files Browse the repository at this point in the history
  • Loading branch information
zh-lx committed Nov 10, 2021
1 parent c6441df commit e6967c0
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 33 deletions.
90 changes: 90 additions & 0 deletions src/mini-react/fiber.js
@@ -1,3 +1,5 @@
import { renderDom } from './react-dom';

let nextUnitOfWork = null;
let rootFiber = null;

Expand All @@ -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;
}
}
}
34 changes: 1 addition & 33 deletions src/mini-react/react-dom.js
Expand Up @@ -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) {
Expand All @@ -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 },
Expand All @@ -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;
Expand Down

0 comments on commit e6967c0

Please sign in to comment.