React 组件渲染和更新的实现代码示例


Posted in Javascript onFebruary 21, 2019

最近一直写React,慢慢就对里面的一些实现很好奇。最好奇的就是自定义标签的实现和this.setState的实现。这里不分析JSX是如何解析的,所有组件都用ES5方式编写。

组件渲染

渲染时候,我们会调用render方法。类似下面这样:

var SayHi = React.createClass({
 getInitialState: function() {
  return {verb: 'say:'};
 },
 componentWillMount: function() {
  console.log('I will mount');
 },
 componentDidMount: function() {
  console.log('I have mounted');
 },
 render: function() {
  return React.createElement("div", null,this.state.verb, "Hello ", this.props.name);
 }
});

React.render(React.createElement(SayHi, {name: "Cynthia"}), document.getElementById("container"));

结果:

页面打印:
say: Hello Cynthia
控制台打印:
I will mount
I have mounted

React 组件渲染和更新的实现代码示例

这是我画的React对象上的一些属性和方法。

当调用render方法时,render会去调用一个map方法,根据传入参数的不同,把被render的对象分为以下三类:
* 文本
* 原生
* 自定义标签

文本

对于文本,React会实例化一个文本节点的对象,并且调用该对象的mount方法。在这个mount方法中,把文本放到一个span中,调用容器组件的innerHTML,进行渲染。

原生标签

对于原生标签,React会实例化一个处理原生标签的对象,并且调用该对象的mount方法。在这个mount方法中,拼接一个字符串,并且不断递归上面的map方法,最后把拼接好的字符串放到容器组件的innerHTML中,进行渲染。

自定义标签

这个应该是大家最好奇的。自定义标签虽然叫标签,其实就是一个类。实例化一个处理自定义标签的对象后,首先React会处理自定义标签的生命周期方法,然后再次递归调用子组件的render方法进而调用map方法,直至把自定义标签分解为前两种标签。

更新

首先,我们统一一下认识。在React里调用this.setState()会使得组件更新,调用this.state = {}只会更改本组件的状态,但是不会使得组件更新。

如果我要更新一个组件,我会这样写。

var SayHi = React.createClass({
 getInitialState: function() {
  return {verb: 'say:'};
 },
 componentWillMount: function() {
  console.log('I will mount');
 },
 componentDidMount: function() {
  console.log('I have mounted');
 },
 changeVerb: function(){
  this.setState({verb: 'write:'});
 }
 render: function() {
  return React.createElement("div", this.changeVerb.bind(this),this.state.verb, "Hello ", this.props.name);
 }
});

React.render(React.createElement(SayHi, {name: "Cynthia"}), document.getElementById("container"));

执行结果:

页面打印:
say: Hello Cynthia
点击文本,页面内容更新成:
write: Hello Cynthia

与更新相关的属性和方法如下:

React 组件渲染和更新的实现代码示例

在调用this.setState()以后,也是调用了一个map方法,根据传入参数不同,依然把要更新的标签分为文本、原生标签、自定义标签三类。具体处理过程如下。

文本

文本节点处理很简单,判断要更新后的文本与当前文本是否===,不是全等就删除原来文本,插入新文本。

自定义标签

对于自定义标签,首先根据对象的引用、key是否相同,判断是否需要更新。如果需要更新,就继续调用上述map方法进行子组件的更新。又是一个递归。但是注意,这里的map方法和渲染部分的map方法不是一个方法哟。

原生标签

对于原生标签,首先更新组件的属性,然后update子树,用diff算法来比较新的子树与目前标签的子树的不同,形成一个差异树,然后用patch方法,把这个差异树更新到真正的DOM树上。

总结

很复杂的过程,让我用流水账写了一遍。没能道出其中精华。以后继续探索,写的详细一些。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript中:表达式和语句的区别[译]
Sep 17 Javascript
select多选 multiple的使用示例
Jun 16 Javascript
一个JavaScript去除字符串末尾的空白实例代码
Sep 22 Javascript
JS实现屏蔽shift,Ctrl,alt等功能键的方法
Jun 01 Javascript
js拖拽的原型声明和用法总结
Apr 04 Javascript
JS实现获取当前URL和来源URL的方法
Aug 24 Javascript
从零学习node.js之利用express搭建简易论坛(七)
Feb 25 Javascript
微信小程序中页面FOR循环和嵌套循环
Jun 21 Javascript
vue操作动画的记录animate.css实例代码
Apr 26 Javascript
了解JavaScript中let语句
May 30 Javascript
基于vue hash模式微信分享#号的解决
Sep 07 Javascript
使用Vue3+Vant组件实现App搜索历史记录功能(示例代码)
Jun 09 Vue.js
vue图片上传本地预览组件使用详解
Feb 20 #Javascript
Vue 后台管理类项目兼容IE9+的方法示例
Feb 20 #Javascript
浅谈小程序 setData学问多
Feb 20 #Javascript
9102年webpack4搭建vue项目的方法步骤
Feb 20 #Javascript
微信小程序五子棋游戏AI实现方法【附demo源码下载】
Feb 20 #Javascript
解决element ui select下拉框不回显数据问题的解决
Feb 20 #Javascript
微信小程序五子棋游戏的悔棋实现方法【附demo源码下载】
Feb 20 #Javascript
You might like
萌王史莱姆”萌王性别尴尬!那“萌战”归女组还是男?
2018/12/17 日漫
ThinkPHP中自定义目录结构的设置方法
2014/08/15 PHP
搭建基于Docker的PHP开发环境的详细教程
2015/07/01 PHP
PHP实现驼峰样式字符串(首字母大写)转换成下划线样式字符串的方法示例
2017/08/10 PHP
基于PHP的加载类操作以及其他两种魔术方法的应用实例
2017/08/28 PHP
Javascript 键盘keyCode键码值表
2009/12/24 Javascript
XENON基于JSON变种
2010/07/27 Javascript
jquery制作弹窗提示窗口代码分享
2014/03/02 Javascript
当某个文本框成为焦点时即清除文本框内容
2014/04/28 Javascript
JavaScript代码轻松实现网页内容禁止复制(代码简单)
2015/10/23 Javascript
jQuery的ajax下载blob文件
2016/07/21 Javascript
javascript 定时器工作原理分析
2016/12/03 Javascript
Three.js开发实现3D地图的实践过程总结
2017/11/20 Javascript
vue.js在标签属性中插入变量参数的方法
2018/03/06 Javascript
angular4强制刷新视图的方法
2018/10/09 Javascript
[54:53]2014 DOTA2国际邀请赛中国区预选赛 LGD-GAMING VS CIS 第二场
2014/05/23 DOTA
[01:13:18]Secret vs Infamous 2019国际邀请赛淘汰赛 败者组 BO3 第一场 8.23
2019/09/05 DOTA
Python Sql数据库增删改查操作简单封装
2016/04/18 Python
详解python while 函数及while和for的区别
2018/09/07 Python
Django之模型层多表操作的实现
2019/01/08 Python
pandas读取CSV文件时查看修改各列的数据类型格式
2019/07/07 Python
Python3中的最大整数和最大浮点数实例
2019/07/09 Python
python使用itchat模块给心爱的人每天发天气预报
2019/11/25 Python
python except异常处理之后不退出,解决异常继续执行的实现
2020/04/25 Python
python正则表达式 匹配反斜杠的操作方法
2020/08/07 Python
html5 canvas-1.canvas介绍(hello canvas)
2013/01/07 HTML / CSS
美国领先的眼镜和太阳镜在线零售商:Glasses.com
2019/08/26 全球购物
酒店led欢迎词
2014/01/09 职场文书
消防标语大全
2014/06/07 职场文书
家长给老师的感谢信
2015/01/20 职场文书
行政文员岗位职责
2015/02/04 职场文书
家庭经济困难证明
2015/06/23 职场文书
民事调解协议书
2016/03/21 职场文书
python实现调用摄像头并拍照发邮箱
2021/04/27 Python
Redis集群的关闭与重启操作
2021/07/07 Redis
GoFrame框架数据校验之校验结果Error接口对象
2022/06/21 Golang