手写简易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、结果

浙公网安备 33010602011771号