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

手写简易React-Fiber的更多相关文章
- JDK动态代理深入理解分析并手写简易JDK动态代理(下)
原文同步发表至个人博客[夜月归途] 原文链接:http://www.guitu18.com/se/java/2019-01-05/27.html 作者:夜月归途 出处:http://www.guitu ...
- JDK动态代理深入理解分析并手写简易JDK动态代理(上)
原文同步发表至个人博客[夜月归途] 原文链接:http://www.guitu18.com/se/java/2019-01-03/27.html 作者:夜月归途 出处:http://www.guitu ...
- 【教程】手写简易web服务器
package com.littlepage.testjdbc; import java.io.BufferedReader; import java.io.FileReader; import ja ...
- 手写简易SpringMVC
手写简易SpringMVC 手写系列框架代码基于普通Maven构建,因此在手写SpringMVC的过程中,需要手动的集成Tomcat容器 必备知识: Servlet相关理解和使用,Maven,Java ...
- 手写简易的Mybatis
手写简易的Mybatis 此篇文章用来记录今天花个五个小时写出来的简易版mybatis,主要实现了基于注解方式的增删查改,目前支持List,Object类型的查找,参数都是基于Map集合的,可以先看一 ...
- Java多线程之Executor框架和手写简易的线程池
目录 Java多线程之一线程及其基本使用 Java多线程之二(Synchronized) Java多线程之三volatile与等待通知机制示例 线程池 什么是线程池 线程池一种线程使用模式,线程池会维 ...
- 手写简易WEB服务器
今天我们来写一个类似于Tomcat的简易服务器.可供大家深入理解一下tomcat的工作原理,本文仅供新手参考,请各位大神指正!首先我们要准备的知识是: Socket编程 HTML HTTP协议 服务器 ...
- 手写简易版RPC框架基于Socket
什么是RPC框架? RPC就是远程调用过程,实现各个服务间的通信,像调用本地服务一样. RPC有什么优点? - 提高服务的拓展性,解耦.- 开发人员可以针对模块开发,互不影响.- 提升系统的可维护性及 ...
- JavaScript之Promise实现原理(手写简易版本 MPromise)
手写 Promise 实现 Promise的基本使用 Promise定义及用法详情文档:Promise MAD文档 function testPromise(param) { return new P ...
随机推荐
- python之线程池和进程池
线程池和进程池 一.池的概念 池是用来保证计算机硬件安全的情况下最大限度的利用计算机 它降低了程序的运行效率但是保证了计算机硬件的安全从而让你写的程序能够正常运行 ''' 无论是开设进程也好还是开设线 ...
- (转载)Quartus II中FPGA的管脚分配保存方法(Quartus II)
一.摘要 将Quartus II中FPGA管脚的分配及保存方法做一个汇总. 二.管脚分配方法 FPGA 的管脚分配,除了在QII软件中,选择"Assignments ->Pin&quo ...
- Linux中断驱动程序
1.中断概念 中断时一种电信号,由硬件设备产生,然后再由中断控制器向处理器发送相应的信号.处理器一经检测到该信号,便中断自己当前正在处理的工作,转而去处理中断.此后,处理器会通知操作系统已经产生中断. ...
- OpenCV计算机视觉学习(4)——图像平滑处理(均值滤波,高斯滤波,中值滤波,双边滤波)
如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice &q ...
- 多测师讲解python_os模块_高级讲师肖sir
#os.path.isfile()#:判断当前是否为文件,返回布尔值是文件则True否者Falsea_path='F:\cms搭建.rar' #lesson包b_path=r'D:\bao\kk '# ...
- Rust之路(2)——数据类型 上篇
[未经书面同意,严禁转载] -- 2020-10-13 -- Rust是系统编程语言.什么意思呢?其主要领域是编写贴近操作系统的软件,文件操作.办公工具.网络系统,日常用的各种客户端.浏览器.记事本. ...
- MySQL【灵魂拷问】
MySQL 一直是本人薄弱的部分,后面会多总结 MySQL 的文章,毕竟 MySQL 涉及到数据存储.锁.磁盘寻道.分页等操作系统概念,而且互联网对 MySQL 的注重程度是不言而喻的,后面要加紧对 ...
- Ubuntu20.04 体验和美化
Ubuntu20.04美化和体验 windows用久了,换下系统也挺好的.ubuntu20.04优化后,用起来蛮舒服的. 系统配置 1.修改软件源 Ubuntu默认是国外的软件源, 我们可以手动切换为 ...
- c++ 遍历目录下文件、文件夹
BOOL GetDirFiles(const char* pszDir, char* pszFileType, std::vector<std::string>& vtFileLi ...
- 没花一分钱的我竟然收到的JetBrains IDEA官方免费赠送一年的Licence
前言 做java的人,一般IDE工具用的不是eclipse就是IntelliJ IDEA了吧,eclipse因为是开源软件,而且起步比较早,功能也比较完善.早期基本上做java的使用eclipse都是 ...