手写简易React-Fiber
阅读原文时间:2023年07月12日阅读:1

1、首先创建createElement函数

1 function createElement (
2 type,
3 config,
4 …children
5 ) {
6
7 const props = {
8 …config,
9 children: children.map(child => typeof child === 'object' ? child : createTextNode(child))
10 }
11
12 return {
13 type,
14 props
15 }
16 }
17
18 function createTextNode (text) {
19
20 return {
21 type: 'TEXT',
22 props:{
23 children:[],
24 nodeValue: text
25 }
26 }
27 }

2、然后创建react-dom,即render函数

1 function render(vnode, container) {
2 //vnode -> node
3 const node = createNode(vnode)
4 //node 插入container
5 console.log(node);
6 node && container && container.appendChild(node)
7 }
8
9 function createNode (vnode) {
10 const {
11 type,
12 props
13 } = vnode
14 let node;
15
16 //根据节点类型生成dom节点
17 if(type === 'TEXT'){
18 //文本
19 node = document.createTextNode('')
20 } else if(typeof type === 'string') {
21 node = document.createElement(type)
22 }
23 //遍历children
24
25 reconcileChildren(node, props ? props.children : [])
26
27 //更新属性
28 updateNode(node, props)
29 return node
30
31 }
32
33 function updateNode(node, nextVal) {
34 if(nextVal){
35 Reflect.ownKeys(nextVal).filter(ck => ck !== 'children').forEach(k => {
36 node[k] = nextVal[k]
37 })
38 }
39 }
40
41 function reconcileChildren(node, children) {
42 children.forEach(child => {
43 render(child,node)
44 })
45 }

3、Fiber实现:

function render(vnode, container) {
//vnode -> node
// const node = createNode(vnode)
//node 插入container
// console.log(node);
// node && container && container.appendChild(node)
// workLoop
wipRoot = {
stateNode: container,
props:{
children:[vnode]
}
}
nextUnitOfWork = wipRoot
}

function createNode (vnode) {
const {
type,
props
} = vnode
let node;

//根据节点类型生成dom节点  
if(type === 'TEXT'){  
    //文本  
    node  = document.createTextNode('')  
} else if(typeof type === 'string') {  
    node = document.createElement(type)  
}  
//遍历children

reconcileChildren(node, props ?  props.children : \[\])

//更新属性  
updateNode(node, props)  
return node

}

function updateNode(node, nextVal) {
if(nextVal){
Reflect.ownKeys(nextVal).filter(ck => ck !== 'children').forEach(k => {
node[k] = nextVal[k]
})
}
}

// function reconcileChildren(node, children) {
// children.forEach(child => {
// render(child,node)
// })
// }
/* fiber */
//next work fiber
let nextUnitOfWork = null
// work in progress 正在工作红的fiber root
let wipRoot = null

function reconcileChildren(workInProgress,children){
let prevNewFiber = null
children.forEach((child,i) => {
//FiberNode 节点
let newFiber = {
type: child.type,
key: child.key,
props:child.props,
stateNode: null,
child: null,
sibling: null,
return:workInProgress
}

    if(i === 0){  
        workInProgress.child = newFiber  
    } else {  
        prevNewFiber.sibling = newFiber  
    }

    prevNewFiber = newFiber  
})  

}

function updateHostComponent(workInProgress){
if(!workInProgress.stateNode){
workInProgress.stateNode = createNode(workInProgress)
}

reconcileChildren(workInProgress,workInProgress.props.children)  

}

function performUnitOfWork(workInProgress) {
//1 处理当前fiber
//原生标签
updateHostComponent(workInProgress)

//2 返回下一个要处理的fiber  
if(workInProgress.child){  
    return workInProgress.child  
}

let next = workInProgress

while(next){  
    if(next.sibling){  
        return next.sibling  
    }  
    next = next.return  
}  

}

//更新Fiber
function workLoop (idleDeadline) {
console.log(idleDeadline);
while(nextUnitOfWork && idleDeadline.timeRemaining() > 1) {
//处理当前fiber 并返回下个fiber
nextUnitOfWork = performUnitOfWork(nextUnitOfWork)
}
//comnitRoot
if(!nextUnitOfWork && wipRoot){
//vnode - node 更新到container中
commitRoot()
}
}

requestIdleCallback(workLoop,{ timeout: 2000 })

function commitRoot() {
commitWorker(wipRoot.child)
wipRoot = null
}

function commitWorker(workInProgress){
if(!workInProgress){
return
}
//提交workInProgress
let parentNodeFiber = workInProgress.return
let parentNode = parentNodeFiber.stateNode
if(workInProgress.stateNode){
parentNode.appendChild(workInProgress.stateNode)
}
//提交 workInProgress.child
commitWorker(workInProgress.child)
//提交 workInProgress.sibling
commitWorker(workInProgress.sibling)
}
// export default { render }

4、最后演示

1
2 3 4 5 手写React 6 7 8 9 10

11 34 35

5、结果

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章