good evening everybody!这是一篇关于react故事的文章,这个故事主要是讲在一个夜黑风高晚上,react从一个VDOM变成真实DOM的过程。

这个过程react经历了从JSX->React.createElement->VDOM->ReactDom.render->真实DOM的大体一个流程。

使用过react的开发者都知道,react一开编写的就是JSX。

以上这段看上去是HTML,但其实它是JSX。什么是JSX?为什么用JSX?它有什么好?

  • JSX是对JS的一个拓展。JSX将HTMl语法直接加入到JS代码中,再通过编译器(Babel-loader)转换成纯JS给浏览器执行。
  • JSX只要用于构建React的View层,类HTML语法,学习成本几乎为零。
  • JSX相对于直接用React.createElement更快,更容易维护,更简洁。

卧槽,怎么说到了JSX里面去了,小编你真不是人,当大佬们什么都不懂啊。

React.createElement又是什么?它能做什么?又是怎样做的???

  • React.createElement是react里面提供的一个核心方法,它可以将JSX转换成VDMO;说是核心方法,但这个放法实现非常简单,就是返回了一个JS对象。

ReactDom.render又是什么?它能做什么?又是怎样做的???

  • ReactDom.render是ReactDom提供的一个核心方法;ReactDom是FB团队故意从react中抽离出来的,但它只能渲染在浏览器。ReactDom.render可以将React.createElement转换成的VDOM,变成真实DOM挂载在浏览器上。

好了,react从VDOM到真实DOM的转换流程概念大概就是这样,现在通过手写React.createElement,React.Component,ReactDom.render三个API(这里实现的三个API,只是负责这个流程的实现,不带任何属性(class,key,ref...)的处理,和diff算法(tree diff,component diff,element diff)之类的东西,是三个极简版的API)

首先,我们通过create-react-app创建一个工程,然后将其他文件删掉,只留下index.js

在src文件在创建一个文件夹(custom)存放自己实现的react(customReact),和react-dom(coutomReactDom)。

index.js

import React from './custom/customReact';import ReactDOM from './custom/customReactDom';let arr = ['su', 'yue', 'feng']function Container(props) {    return 
{props.name}

}class Test extends React.Component { constructor(props) { super(props) } render() { return

{this.props.name} { arr.map(item => {item}) }

}}const JSX = (

普通文本

)ReactDOM.render(JSX, document.getElementById('root'));

以上index.js文件我们写上两个组件,(一个函数组件也叫无状态组件,之从hook出来之后,就不能再叫无状态组件了;一个类组件),还有一些普通标签组件。构成reactVDOM无非就这几种类型。

当我们打包编译的时候,以上的JSX就会被React.createElement转换成VDOM;所以我们在customReact中起码要实现一个createElement方法;如果使用了类组件,还有实现一个Component方法。

function createElement(type, props, ...children) {    let vtype    props.children = children    if (typeof type === 'string') {        vtype = 1    } else if (typeof type === 'function') {        if (type.prototype.render) {            vtype = 2        } else {            vtype = 3        }    }    return { vtype, type, props }}class Component {    constructor(props) {        this.props = props        this.state = {}        this.refs = {}    }    setState() { }        forceUpdate(){}}export default { createElement, Component }

createElement方法接受三个参数,type(标签类型),prop(属性),children(子标签,子属性,这有可能是多个,所以通过es6展开符...,将它们搞成一个数组)。

在createElement里面我们通过type的类型判断他是普通标签,还是组件。如果type是string类型的话,就是普通标签,我们用1表示;如果type是function类型的话,就是组件,但是组件又分函数组件,和类组件,这两种组件,我们用render方法区分,如果又render方法的就是类组件,我们用2表示,没有render方法的就是函数组件,我们用3表示。最后返回一个JS对象。

在Component方法里面,我们什么也不做就是初始换一个变量,setState(),forceUpdate()这两个方法应该大家都不陌生。这里就不去实现,因为这部分的内容太多,涉及到diff,执行机制,更新机制等等,有兴趣的自己去看源码。

最后我们导出这两个方法。

在打包编译的时候,当JSX就会被React.createElement转换成VDOM后,就会执行,react-dom的render方法,这个放法会将VDMO变成真实DOM,所以我们在实现自己的react-dom的时候起码要有一个render方法。

coutomReactDom.js

function render(vnode, container) {    container.appendChild(initVnode(vnode))}function initVnode(vnode) {    if (!vnode.vtype) {        return document.createTextNode(vnode)    }    if (vnode.vtype === 1) {        return createElement(vnode)    } else if (vnode.vtype === 2) {        return createClassCom(vnode)    } else if (vnode.vtype === 3) {        return createFunctionCom(vnode)    }}function createElement(vnode) {    let { type, props: { key, children } } = vnode    let node = document.createElement(type)        children.forEach(element => {        if (Array.isArray(element)) {            element.forEach(c => {                node.appendChild(initVnode(c))            })        } else {            node.appendChild(initVnode(element))        }    });    return node}function createClassCom(vnode) {    let { type, props } = vnode    let instance = new type(props)    return initVnode(instance.render())}function createFunctionCom(vnode) {    let { type, props } = vnode    return initVnode(type(props))}export default { render }

render方法接收两个参数,vnode(虚拟DOM),container(挂载节点)

在render里面,我们通过传进来的虚拟DOM的vtype(也就是我们刚才通过1,2,3,标记的类型)来创建真实的DOM。如果vnode没有vtype的话,我们就通过document.createTextNode(vnode)来创建该文本,如果是1的话,我们就通过createElement方法来创建,createElement方法,只要是通过document.createElement()和递归的方式实现创建节点的流程。如果是2的话,我们就通过createClassCom()方法去创建节点;如果是3的话就通过createFunctionCom()方法去创建节点。这两个方法及其简单加起来就五行代码,这两个方法只要是去拿到组件的虚拟节点,然后给initVnode方法就看可以。因为无论什么组件,到最后还是跑回到创建普通标签的流程,也就是最后还是回到createElement方法里面。

好了,这样就大功告成了,这样就实现了自己的一个react库,俩个文件加起来也只有70行代码。(真正的react里面的做的东西,处理的东西会比这个复杂上千万赔,这里只不过是实现是它从VDOM到真实DOM的转换大概流程)

这是跑起来的效果(npm start)

有不足的地方,希望大佬们指出来。

原文作者:成吉思汗

原文链接:https://segmentfault.com/a/1190000021482301


喜欢小编的可以点个赞关注小编哦,小编每天都会给大家分享文章。

我自己是一名从事了多年的前端老程序员,小编为大家准备了新出的前端编程学习资料,免费分享给大家!

如果你也想学习前端,那么帮忙转发一下然后再关注小编后私信【1】可以得到我整理的这些前端资料了(私信方法:点击我头像进我主页有个上面有个私信按钮)

react的导出是怎么实现的_不到一百行代码,我们来实现一个简简简简简简简简简简版react库...相关推荐

  1. sql相同顺序法和一次封锁法_不到75行代码,导出最高法指导案例到excel(一)...

    2020年7月27日,最高法发布了<统一法律适用 促进司法公正 最高法发布加强类案检索的指导意见>,其中提及类案检索将在2020年7月31日开始试运行. 其中提到的的基本范围包含四个:1) ...

  2. 如何在代码中将menu隐藏_如何在40行代码中将机器学习用于光学/光子学应用

    如何在代码中将menu隐藏 In the last couple of years, Artificial intelligence is finding its use in all sorts o ...

  3. react的导出是怎么实现的_从零开始开发一个 React

    这个是从零开始开发一个 React 系列的第七篇.想要访问之前的内容可以点击下方的链接进行访问: 最简单的实现,包括 vdom 结构,createElement,ReactDOM.render 增加 ...

  4. vant组件实现上传图片裁剪_如何用 120 行代码,实现交互完整的拖拽上传组件?...

    作者 | 前端劝退师 责编 | 伍杏玲 你将在该篇学到: 如何将现有组件改写为 React Hooks函数组件 useState.useEffect.useRef是如何替代原生命周期和Ref的. 一个 ...

  5. python做身份证识别_不到100行代码搞定Python做OCR识别身份证,文字等各种字体

    不告诉你我用了它配合Python简简单单开发OCR识别,带你识别手写体.印刷体.身份证等N种,附代码! 一.你心目中的OCR 在你心目中,OCR是多大(-, 厉害,好厉害,非常厉害,-)呢? 是这么大 ...

  6. python弹幕代码_只需3 行代码就可以获取B站(弹幕、评论、用户)数据

    在今年5月份,我写了一篇爬取B站视频的文章,今天给大家介绍一个获取B站数据的Python扩展库-bilibili_api,可以获取的数据包括: video-视频模块 user-用户模块 dynamic ...

  7. c++编写手机小游戏代码_只需22行代码,用python编写自己的小游戏

    假期最后一天,有些人在外面玩累了,有些人躺在家里快发霉了,闲暇时候不如动动手做个小游戏玩一玩吧! 本文实例为大家分享了python编写猜数字小游戏的具体代码,供大家参考,具体内容如下 1 import ...

  8. java异常在哪一层捕获_当在一个方法的代码中抛出一个检测异常时,该异常或被方法中的 ( )结构 捕获,或者在方法的 ( ) 中声明_学小易找答案...

    [填空题]当异常已经被定义时,必须通过( ) 语句来处理它. [填空题]Catch 子句包含( )的程序段 [单选题]下列java语言的常用异常类中,属于检测异常的是() [单选题]自定义异常类时,可 ...

  9. 拆分工作簿为多个文件_掌握这几行代码,快速拆分Excel工作簿(内含源码)

    工作中,常常会根据工作表的某一内容来拆分工作博并按照指定的命名新建工作簿,且放入指定的路径文件夹下面.今天就拿昨天的例子,来分享一下如何通过几行代码,快速的拆分工作簿 源数据: 目标工作簿及内容: 问 ...

最新文章

  1. ecshop微信扫描支付开发
  2. 用delphi创建服务程式
  3. Xamarin图表开发基础教程(2)OxyPlot框架
  4. Tensorflow Lite Android Demo App
  5. 从0到掌握Java泛型有这一篇博客就够了
  6. Java ByteArrayInputStream reset()方法及示例
  7. C#编码简单性之泛型篇(如何编写简短的C#代码,随时更新)
  8. mongodb mongod 参数解释
  9. 【渝粤教育】电大中专建筑力学 (2)作业 题库
  10. 5. php 基本数据类型
  11. 论文笔记_S2D.17-2018-ECCV-通过卷积空间传播网络(CSPN)的相似性学习进行深度估计
  12. 金蝶KIS商贸版开发销售出库单、销售订单带商品图片打印单据
  13. 深度学习在视频动作识别应用
  14. react customize-cra 配置less modules
  15. 『WEB』web学习
  16. ixigua解析_蓝叶分享西瓜视频地址解析php代码
  17. 如何在工作中保持专注力
  18. 论文导读:CoAtNet是如何完美结合 CNN 和 Transformer的
  19. 图像切割--Seam Carving算法
  20. MATLAB 数学软件

热门文章

  1. GitLab 8.9 新增文件锁 和 U2F硬件支持
  2. 比较好的JavaScript库-日常备用
  3. NodeJS开源项目
  4. 【机器人】9-10月项目疑惑
  5. php ini文件操作类,操作.ini文件的好PHP类
  6. php json数组大小,php json转换成数组形式
  7. 模拟鱼群的matlab算法,IFSA人工鱼群算法
  8. ES6学习笔记(对象新增方法)
  9. 以Debug模式启动JBoss
  10. 不小心删除数据--利用MySQL的binlog恢复数据