看源码一个痛处是会陷进理不顺主干的困局中,本系列文章在实现一个 (x)react 的同时理顺 React 框架的主干内容(JSX/虚拟DOM/组件/生命周期/diff算法/setState/ref/...)

  • 从 0 到 1 实现 React 系列 —— JSX 和 Virtual DOM
  • 从 0 到 1 实现 React 系列 —— 组件和 state|props
  • 从 0 到 1 实现 React 系列 —— 生命周期和 diff 算法
  • 从 0 到 1 实现 React 系列 —— 优化 setState 和 ref 的实现

环境准备

项目打包工具选择了 parcel,使用其可以快速地进入项目开发的状态。快速开始

此外需要安装以下 babel 插件:

"babel-core": "^6.26.0",
"babel-preset-env": "^1.6.1",
"babel-plugin-transform-react-jsx": "^6.24.1"

同时 .babelrc 配置如下:

{"presets": ["env"],"plugins": [// 插件如其名:转化 JSX 语法为定义的形式["transform-react-jsx", {"pragma": "React.createElement"}]]
}

JSX 和 虚拟 DOM

const element = (<div className="title">hello<span className="content">world!</span></div>
)

JSX 是一种语法糖,经过 babel 转换结果如下,可以发现实际上转化成 React.createElement() 的形式:

var element = React.createElement("div",{ className: "title" },"hello",React.createElement("span",{ className: "content" },"world!")
);

打印 element, 结果如下:

{attributes: {className: "title"}children: ["hello", t] // t 和外层对象相同key: undefinednodeName: "div"
}

因此,我们得出结论:JSX 语法糖经过 Babel 编译后转换成一种对象,该对象即所谓的虚拟 DOM,使用虚拟 DOM 能让页面进行更为高效的渲染。

我们按照这种思路进行函数的构造:

const React = {createElement
}function createElement(tag, attr, ...child) {return {attributes: attr,children: child,key: undefined,nodeName: tag,}
}// 测试
const element = (<div className="title">hello<span className="content">world!</span></div>
)console.log(element) // 打印结果符合预期
// {
//   attributes: {className: "title"}
//   children: ["hello", t] // t 和外层对象相同
//   key: undefined
//   nodeName: "div"
// }

虚拟 DOM 转化为真实 DOM

上个小节介绍了 JSX 转化为虚拟 DOM 的过程,这个小节接着来实现将虚拟 DOM 转化为真实 DOM (页面上渲染的是真实 DOM)。

我们知道在 React 中,将虚拟 DOM 转化为真实 DOM 是使用 ReactDOM.render 实现的,使用如下:

ReactDOM.render(element, // 上文的 element,即虚拟 domdocument.getElementById('root')
)

接着来实现 ReactDOM.render 的逻辑:

const ReactDOM = {render
}/*** 将虚拟 DOM 转化为真实 DOM* @param {*} vdom      虚拟 DOM* @param {*} container 需要插入的位置*/
function render(vdom, container) {if (typeof(vdom) === 'string') {container.innerText = vdomreturn}const dom = document.createElement(vdom.nodeName)for (let attr in vdom.attributes) {setAttribute(dom, attr, vdom.attributes[attr])}vdom.children.forEach(vdomChild => render(vdomChild, dom))container.appendChild(dom)
}/*** 给节点设置属性* @param {*} dom   操作元素* @param {*} attr  操作元素属性* @param {*} value 操作元素值*/
function setAttribute(dom, attr, value) {if (attr === 'className') {attr = 'class'}if (attr.match('/on\w+/')) {   // 处理事件的属性:const eventName = attr.toLowerCase().splice(1)dom.addEventListener(eventName, value)} else if (attr === 'style') { // 处理样式的属性:let styleStr = ''let standardCssfor (let klass in value) {standardCss = humpToStandard(klass) // 处理驼峰样式为标准样式styleStr += `${standardCss}: ${value[klass]};`}dom.setAttribute(attr, styleStr)} else {                       // 其它属性dom.setAttribute(attr, value)}
}

至此,我们成功将虚拟 DOM 复原为真实 DOM,展示如下:

另外配合热更新,在热更新的时候清空之前的 dom 元素,改动如下:

const ReactDOM = {render(vdom, container) {container.innerHTML = nullrender(vdom, container)}
}

总结

JSX 经过 babel 编译为 React.createElement() 的形式,其返回结果就是 Virtual DOM,最后通过 ReactDOM.render() 将 Virtual DOM 转化为真实的 DOM 展现在界面上。流程图如下:

思考题

如下是一个 react/preact 的常用组件的写法,那么为什么要 import 一个 React 或者 h 呢?

import React, { Component } from 'react' // react
// import { h, Component } from 'preact' // preactclass A extends Component {render() {return <div>I'm componentA</div>}
}render(<A />, document.body) // 组件的挂载

项目说明

该系列文章会尽可能的分析项目细节,具体的还是以项目实际代码为准。

项目地址

转载于:https://www.cnblogs.com/MuYunyun/p/9274265.html

从 0 到 1 实现 React 系列 —— 1.JSX 和 Virtual DOM相关推荐

  1. 从 0 到 1 实现 React 系列 —— 4.setState优化和ref的实现

    看源码一个痛处是会陷进理不顺主干的困局中,本系列文章在实现一个 (x)react 的同时理顺 React 框架的主干内容(JSX/虚拟DOM/组件/生命周期/diff算法/setState/ref/. ...

  2. 从 0 到 1 实现 React 系列 —— 2.组件和 state|props

    看源码一个痛处是会陷进理不顺主干的困局中,本系列文章在实现一个 (x)react 的同时理顺 React 框架的主干内容(JSX/虚拟DOM/组件/生命周期/diff算法/setState/ref/. ...

  3. 从 0 到 1 实现 React 系列 —— 4.优化setState和ref的实现

    看源码一个痛处是会陷进理不顺主干的困局中,本系列文章在实现一个 (x)react 的同时理顺 React 框架的主干内容(JSX/虚拟DOM/组件/生命周期/diff算法/setState/ref/. ...

  4. 从 0 到 1 实现 React 系列 —— 组件和 state|props

    阅读源码一个痛处是会陷进理不顺主干的困局中,本系列文章在实现一个 (x)react 的同时理顺 React 框架的主干内容(JSX/虚拟DOM/组件/...) 组件即函数 在上一篇 JSX 和 Vir ...

  5. 合格前端系列第五弹- Virtual Dom Diff

    2019独角兽企业重金招聘Python工程师标准>>> 前言 这是一篇很长的文章!!!坚持看到最后有彩蛋哦!!! 文章开篇,我们先思考一个问题,大家都说 virtual dom 这, ...

  6. dispatch作用 react_「React系列」手把手带你撸后台系统(Redux与路由鉴权)

    [React系列]手把手带你撸后台系统(Redux与路由鉴权) 来源:https://juejin.im/post/5d9b5ddee51d45781b63b8f7 上一篇我们介绍了系统架构,这一篇将 ...

  7. React 系列之基础二(状态管理)

    React 系列之基础二 React 状态管理 1.Flux 架构与 Redux 在 Flux 中, 状态完全从 React-components 分离到自己的存储中. 存储中的状态不会直接更改, 而 ...

  8. VMware View 5.0从菜鸟到高手系列 10 –远程图形工作站配置篇

    本文档依照PCoIP设备供应商丽台(Leadtek)提供的零客户机VP200P以及PCoI卡VP200H为例,为了介绍整个安装步骤.以下配置在VMware view 4.5中安装,但在更新的版本中如V ...

  9. React Native 0.59.0 发布,使用 React 编写原生应用

    React Native 0.59.0 发布了.React Native 使开发者只使用 JavaScript 也能编写原生移动应用. 新版更新亮点: React Hooks React Native ...

最新文章

  1. EditPlus正则表达式
  2. LeetCode Contains Duplicate III(滑动窗口)
  3. spring-security问题记录
  4. Spring MVC的表单控制器——SimpleFormController .
  5. python 混淆矩阵_绘制混沌矩阵
  6. 前端学习(2087):v-on得修饰符使用案例
  7. 准大学生的实用省钱小技巧
  8. php 保护连接字符串,PHP OOP更新扩展类__construct上的受保护字符串
  9. 亚马逊服务器维护,Amazon EC2 维护帮助页面
  10. python 脚本_基于Python的ArcGIS脚本编程知识点总结
  11. STM32工作笔记0096---用sprintf分配内存
  12. python自学免费教程-python免费入门教程/求完整的Python入门教程
  13. jQuery实现留言板
  14. Win10个人使用软件清单
  15. vs下inl中的函数提示C2084 已有主体的解决方案
  16. 经济学计算机会成本和贸易区直的题,管理经济学2017年4月真题(02628)
  17. vue 组件名称错误
  18. Adobe photoshop 用户名、组织或序列号丢失或无效的解决方法
  19. python操作浏览器滚动条_python selenium webdriver处理浏览器滚动条
  20. 怎样读书(繁体版)读书笔记

热门文章

  1. python中turtle画圆填充颜色_Python之turtle绘图
  2. java有没有友元函数_c++中友元函数理解与使用
  3. win8计算机配置怎么看,win8怎么看电脑配置?win8电脑配置的查看方法
  4. linux命令行发送串口_从命令行在Linux中发送电子邮件
  5. mongodb卸载_如何在Windows上安装MongoDB,启动,卸载
  6. 使用Spring Boot CLI的Spring Boot Initilizr
  7. 如何在Shell脚本中使用if-else?
  8. Total Commander 常用快捷键
  9. jmeter之线程组间变量的传递二
  10. OpenGL ES应用开发实践指南:iOS卷