1、首先创建createElement函数

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

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

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

3、Fiber实现:

  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. // workLoop
  8. wipRoot = {
  9. stateNode: container,
  10. props:{
  11. children:[vnode]
  12. }
  13. }
  14. nextUnitOfWork = wipRoot
  15. }
  16.  
  17. function createNode (vnode) {
  18. const {
  19. type,
  20. props
  21. } = vnode
  22. let node;
  23.  
  24. //根据节点类型生成dom节点
  25. if(type === 'TEXT'){
  26. //文本
  27. node = document.createTextNode('')
  28. } else if(typeof type === 'string') {
  29. node = document.createElement(type)
  30. }
  31. //遍历children
  32.  
  33. reconcileChildren(node, props ? props.children : [])
  34.  
  35. //更新属性
  36. updateNode(node, props)
  37. return node
  38.  
  39. }
  40.  
  41. function updateNode(node, nextVal) {
  42. if(nextVal){
  43. Reflect.ownKeys(nextVal).filter(ck => ck !== 'children').forEach(k => {
  44. node[k] = nextVal[k]
  45. })
  46. }
  47. }
  48.  
  49. // function reconcileChildren(node, children) {
  50. // children.forEach(child => {
  51. // render(child,node)
  52. // })
  53. // }
  54. /* fiber */
  55. //next work fiber
  56. let nextUnitOfWork = null
  57. // work in progress 正在工作红的fiber root
  58. let wipRoot = null
  59.  
  60. function reconcileChildren(workInProgress,children){
  61. let prevNewFiber = null
  62. children.forEach((child,i) => {
  63. //FiberNode 节点
  64. let newFiber = {
  65. type: child.type,
  66. key: child.key,
  67. props:child.props,
  68. stateNode: null,
  69. child: null,
  70. sibling: null,
  71. return:workInProgress
  72. }
  73.  
  74. if(i === 0){
  75. workInProgress.child = newFiber
  76. } else {
  77. prevNewFiber.sibling = newFiber
  78. }
  79.  
  80. prevNewFiber = newFiber
  81. })
  82. }
  83.  
  84. function updateHostComponent(workInProgress){
  85. if(!workInProgress.stateNode){
  86. workInProgress.stateNode = createNode(workInProgress)
  87. }
  88.  
  89. reconcileChildren(workInProgress,workInProgress.props.children)
  90. }
  91.  
  92. function performUnitOfWork(workInProgress) {
  93. //1 处理当前fiber
  94. //原生标签
  95. updateHostComponent(workInProgress)
  96.  
  97. //2 返回下一个要处理的fiber
  98. if(workInProgress.child){
  99. return workInProgress.child
  100. }
  101.  
  102. let next = workInProgress
  103.  
  104. while(next){
  105. if(next.sibling){
  106. return next.sibling
  107. }
  108. next = next.return
  109. }
  110. }
  111.  
  112. //更新Fiber
  113. function workLoop (idleDeadline) {
  114. console.log(idleDeadline);
  115. while(nextUnitOfWork && idleDeadline.timeRemaining() > 1) {
  116. //处理当前fiber 并返回下个fiber
  117. nextUnitOfWork = performUnitOfWork(nextUnitOfWork)
  118. }
  119. //comnitRoot
  120. if(!nextUnitOfWork && wipRoot){
  121. //vnode - node 更新到container中
  122. commitRoot()
  123. }
  124. }
  125.  
  126. requestIdleCallback(workLoop,{ timeout: 2000 })
  127.  
  128. function commitRoot() {
  129. commitWorker(wipRoot.child)
  130. wipRoot = null
  131. }
  132.  
  133. function commitWorker(workInProgress){
  134. if(!workInProgress){
  135. return
  136. }
  137. //提交workInProgress
  138. let parentNodeFiber = workInProgress.return
  139. let parentNode = parentNodeFiber.stateNode
  140. if(workInProgress.stateNode){
  141. parentNode.appendChild(workInProgress.stateNode)
  142. }
  143. //提交 workInProgress.child
  144. commitWorker(workInProgress.child)
  145. //提交 workInProgress.sibling
  146. commitWorker(workInProgress.sibling)
  147. }
  148. // export default { render }

4、最后演示

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

5、结果

手写简易React-Fiber的更多相关文章

  1. JDK动态代理深入理解分析并手写简易JDK动态代理(下)

    原文同步发表至个人博客[夜月归途] 原文链接:http://www.guitu18.com/se/java/2019-01-05/27.html 作者:夜月归途 出处:http://www.guitu ...

  2. JDK动态代理深入理解分析并手写简易JDK动态代理(上)

    原文同步发表至个人博客[夜月归途] 原文链接:http://www.guitu18.com/se/java/2019-01-03/27.html 作者:夜月归途 出处:http://www.guitu ...

  3. 【教程】手写简易web服务器

    package com.littlepage.testjdbc; import java.io.BufferedReader; import java.io.FileReader; import ja ...

  4. 手写简易SpringMVC

    手写简易SpringMVC 手写系列框架代码基于普通Maven构建,因此在手写SpringMVC的过程中,需要手动的集成Tomcat容器 必备知识: Servlet相关理解和使用,Maven,Java ...

  5. 手写简易的Mybatis

    手写简易的Mybatis 此篇文章用来记录今天花个五个小时写出来的简易版mybatis,主要实现了基于注解方式的增删查改,目前支持List,Object类型的查找,参数都是基于Map集合的,可以先看一 ...

  6. Java多线程之Executor框架和手写简易的线程池

    目录 Java多线程之一线程及其基本使用 Java多线程之二(Synchronized) Java多线程之三volatile与等待通知机制示例 线程池 什么是线程池 线程池一种线程使用模式,线程池会维 ...

  7. 手写简易WEB服务器

    今天我们来写一个类似于Tomcat的简易服务器.可供大家深入理解一下tomcat的工作原理,本文仅供新手参考,请各位大神指正!首先我们要准备的知识是: Socket编程 HTML HTTP协议 服务器 ...

  8. 手写简易版RPC框架基于Socket

    什么是RPC框架? RPC就是远程调用过程,实现各个服务间的通信,像调用本地服务一样. RPC有什么优点? - 提高服务的拓展性,解耦.- 开发人员可以针对模块开发,互不影响.- 提升系统的可维护性及 ...

  9. JavaScript之Promise实现原理(手写简易版本 MPromise)

    手写 Promise 实现 Promise的基本使用 Promise定义及用法详情文档:Promise MAD文档 function testPromise(param) { return new P ...

随机推荐

  1. SolrCloud搭建

    什么是SolrCloud? SolrCloud是基于 solr 和 zookeeper 的分布式搜索方案,它的主要思想是使用zookeeper作为SolrCloud集群的配置信息中心,统一管理Solr ...

  2. Word+Excel 问题及解决

    [Word] 快捷操作 (1)每个字后面都有换行符的处理办法: 替换:∧p -> 空格 (2)隐藏Word文档中的换行符: word选项 -> 显示 -> 段落标记 [Excel]

  3. swoole父进程和子进程之间通信的例子

    <?php /** 这是一个swoole父进程和子进程之间通信的例子 */ //进程创建成功后回调处理 function handle(swoole_process $worker){ //从进 ...

  4. 持续集成工具之Jenkins使用配置

    在上一篇博客中,我们主要介绍了DevOps理念以及java环境和jenkins的安装,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/13805666.html: ...

  5. 怎样学好 java ?

    浅谈Java的学习之路--怎样学好JAVA ?Java - 近10年来计算机软件发展过程中的传奇,其在众多开发者心中的地位就如"屠龙刀"."倚天剑". Java ...

  6. day02 Pyhton学习

    1.昨日内容回顾 1.python是一门解释型,弱类型的高级编程语言 优点: 1.优雅简单明确 2.短小快,代码短,代码量小,开发效率高 缺点: 1.运行效率低(相对) 2.python解释器 Cpy ...

  7. k8s- centos7.8搭建

    vmware16.0 centos7.8 1. 使用vmware安装 centos环境  cpu4个 内存4G 网络nat模式 2.配置网络 vim /etc/sysconfig/network-sc ...

  8. 并发压测 jmeter使用教程

    百度网盘下载软件 提取码: 2nur 第一步:首先从jmeter的官网下载jmeter,目前最新版本为4.0,支持的JDK最高为1.8 下载地址: jmeter:http://jmeter.apach ...

  9. spring boot:redis+lua实现顺序自增的唯一id发号器(spring boot 2.3.1)

    一,为什么需要生成唯一id(发号器)? 1,在分布式和微服务系统中, 生成唯一id相对困难, 常用的方式: uuid不具备可读性,作为主键存储时性能也不够好, mysql的主键,在分库时使用不够方便, ...

  10. centos8上安装mysql8

    一,下载并解压mysql8 1,mysql官网 https://www.mysql.com/ 2,下载到source目录 [root@yjweb source]# wget https://cdn.m ...