手写简易React-Fiber

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 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="utf-8">
 5         <title>手写React</title>
 6         <script src="main.js" type="text/javascript" charset="utf-8"></script>
 7         <script src="treact-dom.js" type="text/javascript" charset="utf-8"></script>
 8     </head>
 9     <body>
10         <div id="root"></div>
11         <script type="text/javascript">
12             let rot = createElement(
13                "div",
14                 null,
15                 createElement(
16                   "h1",
17                   null,
18                   "慢 慢 慢"
19                 ),
20                 createElement(
21                   "p",
22                   null,
23                   "Terry"
24                 ),
25                 createElement(
26                   "a",
27                   { href: "https://www.kaikeba.com/" },
28                   "Terry"
29                 ),
30                 "哈哈哈哈"
31             )
32             render(rot, document.getElementById("root"))
33         </script>
34     </body>
35 </html>

5、结果

 

posted @ 2020-10-22 10:04  广广-t  阅读(185)  评论(0)    收藏  举报