手写简易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 ...
随机推荐
- SolrCloud搭建
什么是SolrCloud? SolrCloud是基于 solr 和 zookeeper 的分布式搜索方案,它的主要思想是使用zookeeper作为SolrCloud集群的配置信息中心,统一管理Solr ...
- Word+Excel 问题及解决
[Word] 快捷操作 (1)每个字后面都有换行符的处理办法: 替换:∧p -> 空格 (2)隐藏Word文档中的换行符: word选项 -> 显示 -> 段落标记 [Excel]
- swoole父进程和子进程之间通信的例子
<?php /** 这是一个swoole父进程和子进程之间通信的例子 */ //进程创建成功后回调处理 function handle(swoole_process $worker){ //从进 ...
- 持续集成工具之Jenkins使用配置
在上一篇博客中,我们主要介绍了DevOps理念以及java环境和jenkins的安装,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/13805666.html: ...
- 怎样学好 java ?
浅谈Java的学习之路--怎样学好JAVA ?Java - 近10年来计算机软件发展过程中的传奇,其在众多开发者心中的地位就如"屠龙刀"."倚天剑". Java ...
- day02 Pyhton学习
1.昨日内容回顾 1.python是一门解释型,弱类型的高级编程语言 优点: 1.优雅简单明确 2.短小快,代码短,代码量小,开发效率高 缺点: 1.运行效率低(相对) 2.python解释器 Cpy ...
- k8s- centos7.8搭建
vmware16.0 centos7.8 1. 使用vmware安装 centos环境 cpu4个 内存4G 网络nat模式 2.配置网络 vim /etc/sysconfig/network-sc ...
- 并发压测 jmeter使用教程
百度网盘下载软件 提取码: 2nur 第一步:首先从jmeter的官网下载jmeter,目前最新版本为4.0,支持的JDK最高为1.8 下载地址: jmeter:http://jmeter.apach ...
- spring boot:redis+lua实现顺序自增的唯一id发号器(spring boot 2.3.1)
一,为什么需要生成唯一id(发号器)? 1,在分布式和微服务系统中, 生成唯一id相对困难, 常用的方式: uuid不具备可读性,作为主键存储时性能也不够好, mysql的主键,在分库时使用不够方便, ...
- centos8上安装mysql8
一,下载并解压mysql8 1,mysql官网 https://www.mysql.com/ 2,下载到source目录 [root@yjweb source]# wget https://cdn.m ...