# react_fiber
**Repository Path**: aeipyuan/react_fiber
## Basic Information
- **Project Name**: react_fiber
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-05-29
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## 生成`virtual DOM`树
bable转换jsx的结果
```jsx
let style = { border: "1px solid orange", margin: "5px" }
let element = (
)
//babel解析结果:
// React.createElement("div", { id: "A1", style: style },
// " A1",
// React.createElement("div", { id: "B1", style: style },
// " B1",
// React.createElement("div", { id: "C1", style: style }, "C1"),
// React.createElement("div", { id: "C2", style: style }, "C2")
// ),
// React.createElement("div", { id: "B2", style: style }, "B2")
// );
```
实现createElment
```javascript
import { ELEMENT_TEXT } from './constants'
function createElement(type, props, ...children) {
delete props.__source;
delete props.__self;
return {
type,
props: {
...props,
children: children.map(child => {
/* 文本节点特殊处理 */
return typeof child === 'object' ? child : {
type: ELEMENT_TEXT,
props: { text: child, children: [] }
}
})
}
}
}
```
React.createElement处理过后的`virtual DOM`

## 实现render方法
render使用
```javascript
ReactDOM.render(
element,
document.getElementById('root')
);
```
react-dom入口文件
```javascript
import { TAG_ROOT } from "../react/constants"
import scheduleRoot from './schedule'
function render(element, container) {
/* 根fiber */
let rootFiber = {
tag: TAG_ROOT,
stateNode: container,
props: { children: [element] }
};
scheduleRoot(rootFiber);
}
export default { render}
```
### 1. 初始化
```javascript
let wrokProgressRoot = null;//记录根节点
let nextUnitOfWork = null;//记录当前工作单元
function scheduleRoot(rootFiber) {
wrokProgressRoot = rootFiber;
nextUnitOfWork = rootFiber;
}
```
### 2. 工作循环
`requestIdleCallback`作用
实现在浏览器空闲时运行`workLoop`,若超过500ms之不管是否空闲都运行(60帧显示器每16.6ms刷新一次,存在空闲时间则执行`performUnitOfwork`,一直到达500ms无空闲时间则强制执行)
```javascript
// 工作循环
function workLoop(deadline) {
// 时间片未到
if ((deadline.timeout || deadline.timeRemaining() > 0) && nextUnitOfWork) {
/* 执行工作单元,返回下一单元 */
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
/* 还有工作单元未执行 */
if (!nextUnitOfWork && wrokProgressRoot) {
console.log("Render 完成");
// 生成DOM
commitRoot();
}
requestIdleCallback(workLoop, { timeout: 500 });
}
requestIdleCallback(workLoop, { timeout: 500 });
```
#### 2.1 performUnitOfWork执行工作单元
```javascript
function performUnitOfWork(currentFiber) {
//构建
beginWork(currentFiber);
/* 子元素 */
if (currentFiber.child) {
return currentFiber.child;
}
/* 没有子元素释放自己并往上找 */
while (currentFiber) {
/* fiber子元素全部完成,将自身合并到副作用链 */
completeUnitOfWork(currentFiber);
if (currentFiber.sibling) {
return currentFiber.sibling;
}
/* 往上找 */
currentFiber = currentFiber.return;
}
}
```
#### 2.1.1 beginWork分类构建
```javascript
function beginWork(currentFiber) {
//根元素
if (currentFiber.tag === TAG_ROOT) {
upDateRoot(currentFiber);
}
//原生节点
if (currentFiber.tag === TAG_HOST) {
upDateHost(currentFiber);
}
//文本节点
if (currentFiber.tag === TAG_TEXT) {
upDateText(currentFiber);
}
}
/* 更新根元素 */
function upDateRoot(currentFiber) {
/* 构建子元素 */
let newChildren = currentFiber.props.children;
reconcileChildren(currentFiber, newChildren);
}
/* 更新原生元素 */
function upDateHost(currentFiber) {
/* 创建DOM */
if (!currentFiber.stateNode) {
currentFiber.stateNode = createDOM(currentFiber);
}
/* 获取并构建子元素 */
let newChildren = currentFiber.props.children;
reconcileChildren(currentFiber, newChildren);
}
/* 更新文本元素 */
function upDateText(currentFiber) {
if (!currentFiber.stateNode) {
currentFiber.stateNode = createDOM(currentFiber);
}
}
```
createDOM方法创建Dom,设置属性
```javascript
/* 创建DOM */
function createDOM(currentFiber) {
if (currentFiber.tag === TAG_TEXT) {
/* 直接船舰文本节点 */
return document.createTextNode(currentFiber.props.text);
}
else if (currentFiber.tag === TAG_HOST) {
let stateNode = document.createElement(currentFiber.type);//
setProps(stateNode, {}, currentFiber.props);
//
return stateNode;
}
}
```
reconcileChildren遍历子节点并记录父子兄弟fiber关系

```javascript
/* 创建子元素fiber并连接到父元素上 */
function reconcileChildren(returnFiber, newChildren) {
let newChildIndex = 0,prevSibling = null;
//遍历returnFiber的子节点
while (newChildIndex < newChildren.length) {
let newChild = newChildren[newChildIndex];
/* 标识文本和原生组件 */
let tag;
if (newChild.type === ELEMENT_TEXT) {
tag = TAG_TEXT;
} else if (typeof newChild.type === "string") {
tag = TAG_HOST;
}
/* 创建Fiber */
let newFiber = {
tag,
type: newChild.type,
props: newChild.props,
stateNode: null,
return: returnFiber,//父节点
effectTag: PLACEMENT,//操作
nextEffect: null//下一个节点
}
/* 连接Fiber,第一个子元素作为儿子,其他作为兄弟连接 */
if (newChildIndex === 0) {
returnFiber.child = newFiber;
} else {
prevSibling.sibling = newFiber;
}
prevSibling = newFiber;
newChildIndex++;
}
}
```
#### 2.1.2 completeUnitOfWork构建副作用链

```javascript
function completeUnitOfWork(currentFiber) {
/* 获取父节点 */
let returnFiber = currentFiber.return;
if (returnFiber) {
/* 将自己连接到父元素 */
if (!returnFiber.firstEffect) {
returnFiber.firstEffect = currentFiber.firstEffect;
}
if (currentFiber.lastEffect) {
/* 将当前fiber头部接到父fiber尾部 */
if (returnFiber.lastEffect) {
returnFiber.lastEffect.nextEffect = currentFiber.firstEffect;
}
/* 当前尾部作为最终尾部 */
returnFiber.lastEffect = currentFiber.lastEffect;
}
/* 连接子元素 */
if (currentFiber.effectTag === PLACEMENT) {
/* 当前元素尾部有元素才会连接 */
if (returnFiber.lastEffect) {
returnFiber.lastEffect.nextEffect = currentFiber;
} else {
returnFiber.firstEffect = currentFiber;
}
/* 更新尾巴 */
returnFiber.lastEffect = currentFiber;
}
}
}
```
#### 2.2 commit挂载DOM
```javascript
function commitWork(currentFiber) {
/* 获取父元素 */
let returnDom = currentFiber.return.stateNode;
/* 副作用类型 */
if (currentFiber.effectTag === PLACEMENT) {
returnDom.appendChild(currentFiber.stateNode);
}
/* 去除副作用 */
currentFiber.effectTag = null;
}
function commitRoot() {
/* 获取链表头 */
let currentFiber = wrokProgressRoot.firstEffect;
while (currentFiber) {
commitWork(currentFiber);
currentFiber = currentFiber.nextEffect;
}
wrokProgressRoot = null;
}
```
## 总结
ReactDOM的render方法首先将虚拟DOM树进行扩充,记录节点的孩子和兄弟,然后将副作用节点按照自底向上的顺序记录在一个链表中,commit时实现从里到外改变DOM。