手写简易React-Fiber
2024-08-30 08:18:18
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、结果
最新文章
- Android提交数据到JavaWeb服务器实现登录
- wordpress数据库表说明
- 利用Delphi的File Of Type创建并管理属于你自己的数据库
- MongoDB的安装 转
- 获得输入框的文本document.getElementById(&#39;id&#39;).value;
- Codeforces Round #382 (Div. 2) D. Taxes 歌德巴赫猜想
- 无线 WIFI 的13个信道频率范围
- Mindjet MindManager 2012 从模板创建出现“Runtime Error pure virtual function call” 解决方法
- oracle Recyclebin
- Fiddler教程【转】
- 「JavaScript」同步、异步、回调执行顺序之经典闭包setTimeout分析
- Hadoop API:遍历文件分区目录,并根据目录下的数据进行并行提交spark任务
- [2019.03.16]使用DOM操作函数和CSS选择器来针对已有的HTML进行只凭JS的改动
- UVa 10970 - Big Chocolate 水题 难度: 0
- 分布式控制系统Git学习
- django —— MVT模型
- DropEditText
- Redis实现聊天功能
- spring揭密学习笔记(1) --spring的由来
- O​r​a​c​l​e​ ​1​1​g​ ​客​户​端​安​装​及​p​l​s​q​l​配​置
热门文章
- 【面试题】java一般
- 扫描仪扫描文件处理-Photoshop批处理无响应问题
- spring boot:spring security实现oauth2授权认证(spring boot 2.3.3)
- lerna管理前端模块实践
- IDEA出现Error Loading Project: Cannot load module xxx报错
- LinkedHashMap 实现LRU缓存
- MFiX中DEM颗粒信息随时间变化
- Swagger配置与使用
- Spark为什么只有在调用action时才会触发任务执行呢(附算子优化和使用示例)?
- python数据类型之String(字符串)