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 相关文章推荐
鼠标经过的文本框textbox变色
May 21 Javascript
11款新鲜的jQuery插件[附所有demo下载]
Jan 24 Javascript
jquery focus(fn),blur(fn)方法实例代码
Dec 16 Javascript
jquery实现metro效果示例代码
Sep 06 Javascript
基于jQuery下拉选择框插件支持单选多选功能代码
Jun 07 Javascript
学习Angular中作用域需要注意的坑
Aug 17 Javascript
JSON与String互转的实现方法(Javascript)
Sep 27 Javascript
Bootstrap CSS组件之输入框组
Dec 17 Javascript
5分钟快速掌握JS中var、let和const的异同
Sep 19 Javascript
详解微信小程序框架wepy踩坑记录(与vue对比)
Mar 12 Javascript
详解vue 命名视图
Aug 14 Javascript
JavaScript中条件语句的优化技巧总结
Dec 04 Javascript
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
elgg 获取文件图标地址的方法
2010/03/20 PHP
PHP实现克鲁斯卡尔算法实例解析
2014/08/22 PHP
php/JS实现的生成随机密码(验证码)功能示例
2019/06/06 PHP
Laravel 实现添加多语言提示信息
2019/10/25 PHP
PHP字符串和十六进制如何实现互相转换
2020/07/16 PHP
Javascript图像处理—虚拟边缘介绍及使用方法
2012/12/27 Javascript
JavaScript实现多维数组的方法
2013/11/20 Javascript
JS获取url链接字符串 location.href
2013/12/23 Javascript
js动画效果制件让图片组成动画代码分享
2014/01/14 Javascript
js中数组结合字符串实现查找(屏蔽广告判断url等)
2016/03/30 Javascript
快速解决jquery.touchSwipe左右滑动和垂直滚动条冲突
2016/04/15 Javascript
浅析angularJS中的ui-router和ng-grid模块
2016/05/20 Javascript
老生常谈 关于JavaScript的类的继承
2016/06/24 Javascript
jquery利用json实现页面之间传值的实例解析
2016/12/12 Javascript
arcgis for js栅格图层叠加(Raster Layer)问题
2017/11/22 Javascript
nodejs调取微信收货地址的方法
2017/12/20 NodeJs
JS脚本加载后执行相应回调函数的操作方法
2018/02/28 Javascript
微信小程序实现即时通信聊天功能的实例代码
2018/08/17 Javascript
vue-cli构建vue项目的步骤详解
2019/01/27 Javascript
详解小程序如何避免多次点击,重复触发事件
2019/04/08 Javascript
Vue中错误图片的处理的实现代码
2019/11/07 Javascript
一篇文章带你搞懂Vue虚拟Dom与diff算法
2020/08/25 Javascript
Falsk 与 Django 过滤器的使用与区别详解
2019/06/04 Python
Django集成MongoDB实现过程解析
2020/12/01 Python
python利用opencv实现颜色检测
2021/02/23 Python
New Balance天猫官方旗舰店:始于1906年,百年慢跑品牌
2017/11/15 全球购物
技术副厂长岗位职责
2013/12/26 职场文书
效能监察建议书
2014/05/19 职场文书
幼儿园课题方案
2014/06/09 职场文书
低碳环保口号
2014/06/12 职场文书
2015年大学元旦晚会活动策划书
2014/12/09 职场文书
安全知识竞赛主持词
2015/06/30 职场文书
《伯牙绝弦》教学反思
2016/02/16 职场文书
Nginx代理同域名前后端分离项目的完整步骤
2021/03/31 Servers
如何用python插入独创性声明
2021/03/31 Python
Golang 空map和未初始化map的注意事项说明
2021/04/29 Golang