说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

探索React:组件间通信过程解析

HTML文档下载 WORD文档下载 PDF文档下载
《The React.js Way》系列博文重点分享React所具特性及最佳开发实践。本文为第二篇的译文,重点探讨了React组件间相互通信过程。

近日,RisingStack CTO Péter Márton正在陆续发表《The React.js Way》系列博文,第一篇文章以分享React.js的核心入门知识(中文译文)为主,并讨论了虚拟DOM的概念,以及如何使用组件的思维方式来思考开发的基础上。接下来,需要将它们组合起来运用到实战中去, 第二篇文章则以此为出发点,探讨了React的组件间是如何进行相互通信的。感谢景庄对第二篇文章的翻译,内容如下:

组件即是函数

对于一个独立组件而言,你可以把它看成是一个JavaScript函数。对于函数而言,当你通过传递参数调用函数时,函数会返回给你一个值。 相比之下,对于React组件而言,道理是相似的,你传递属性给组件,而组件则会返回一个被渲染好的DOM。通过传递不同的数据, 相应的你会得到不同的响应。这个过程也就使得React组件能够得到极大的复用,并且你可以很轻松的在应用中重用和组装这些组件。 这种思想实际来源于函数式编程,但其并不在本文的讨论范围中。如果你感兴趣的话,那我强烈建议你阅读Mikael Brevik的 《 Functional UI and Components as Higher Order Functions》, 它可以帮助你更好的理解这个话题。

自上而下渲染

目前为止,我们可以轻松地通过组装组件的方式来构建应用,但此之前,在组件中并没有包括数据。在第一篇文章中,我们讨论过可以在组件层次中的根组件中通过将数据作为参数传递给组件,并且通过层层传递的方式将数据传递给下层组件,也就是说,你在顶层传递数据,它可以一层一层地往下传递, 这个过程,我们称之为自上而下的渲染。


从上层组件往下层组件传递数据其实很简单,但是,如果下层组件发生了某些变化,我们如何通知上层组件呢?例如,用户点击了某个按钮? 我们需要某个东西来存放应用程序的状态数据,能够在状态发生变化的时候去通知所发生的变化。新的状态应该能够被传递给根节点 (最上层节点),然后应该再次发起自上而下的渲染,从而重新生成(渲染)DOM。为了解决这个问题,Facebook提出了Flux架构。

Flux架构

你可能已经听过什么是Flux,也了解它是一种类似于MVC的应用程序设计架构,因此本文不会过多的去探讨什么是Flux,感兴趣的话, 可以阅读《 Flux Inspired libraires with React》这篇文章。

构建用户界面的应用程序架构 —— Facebook Flux

简单总结下:Flux倡导的是单向数据流的原则,在这种架构下,通过Store存放应用程序的状态数据。当应用状态发生变化时,Store可以发出事件,通知应用的组件并进行组件的重新渲染。另外,Dispatcher起到中央hub的作用,它为组件(View)和Store构建起了桥梁。此外,你可以在组件上调用action,它会向Store发起事件。Store正是通过订阅这些事件,并根据事件的触发来改变应用程序的内部状态的。


PureRenderMixin

目前对于我们的应用而言,我们通过一个数据store来存放应用的实际状态。我们可以和这个store进行通信,将数据传递到我们的应用上, 当组件获取新的数据后,进而对视图进行重新渲染。这听起来很赞,但总感觉会经历很多次的渲染,的确是这样的!需要记住的是:组件的层次关系和自然而下的渲染,一切都会根据新的数据来进行响应,做出相应的变化。

在这之前的文章中,我们讨论过虚拟DOM通过一种更为优雅的方式降低了DOM操纵带来的性能损耗,但这并不意味着我们就不需要自己手动进行性能优化了。 对此,基于当前数据和新来的数据之间的差异,我们应该能够告诉组件对于新来的数据是否需要进行视图的重新渲染(如果数据没有发生变化,应该不再重新渲染)。在React的生命周期中,你可以借助shouldComponentUpdate来达成这一目的。

幸运的是,在React中有一种被称为PureRenderMixin的Mixin模式,它可以用来对新的属性和之前的属性进行对比,如果是数据没有发生变化,就不再重新渲染。在内部实现上,它也是基于shouldComponentUpdate 方法的。

这听起来很赞,但遗憾的是,PureRenderMixin并不能很好地进行对象的比较。它只会检查对象引用的相等性(===),也就是说, 对于有相同数据的不同对象而言它会返回false。

boolean shouldComponentUpdate(object nextProps, object nextState)
如果shouldComponentUpdate返回的是false的话,render函数便会跳过,直到状态再次发生改变。(此外,componentWillUpdate和componentDidUpdate也会被跳过)。对于上面所说的问题,我们可以简单的举个例子来说明,有代码如下:

var a = { foo: 'bar' };  var b = { foo: 'bar' };a === b; // false  
可以看到,数据是相同的,但它们隶属于不同对象的引用,因此返回的是false,也因此组件仍然会进行重新渲染,显然这没有达到我们的目的。如果我们想要达成设想的效果(即对于相同数据而言,组件不再重新渲染),我们就需要在原始的对象上进行数据的修改:

var a = { foo: 'bar' };  var b = a;  b.foo = 'baz';  a === b; // true  

虽然实现一个能够进行深度对象比较的mixin来代替引用检查并不困难,但是,考虑到React调用shouldComponentUpdate方法非常频繁,并且对象的深度检查代价较高,所以React选择了这种对象引用比较的方案。

我非常建议你阅读Facebook官方的 有关React应用高级性能的文档。

不变性 Immutability

如果我们的应用状态是一个单一的、大的、嵌套的对象(类似于Flux中的Store),那么上面提到的问题会逐渐升级。

所以当对象的内容没有发生变化时,或者有一个新的对象进来时,我们倾向于保持对象引用的不变。这个工作正是我们需要借助Facebook的Immutable.js来完成的。

不变性意味着数据一旦创建就不能被改变,这使得应用开发更为简单,避免保护性拷贝(defensive copy),并且使得在简单的应用逻辑中实现变化检查机制等。

下面通过一个例子来解释下上面的话。比如,有如下的代码片段:

如上,我们可以使用===来通过引用来比较对象,这意味着我们能够方便快速的进行对象比较,并且它能够和React中的PureRenderMixin 兼容。基于此,我们可以在整个应用构建中使用Immutable.js。也就是说,我们的Flux Store应该是一个具有不变性的对象,并且我们通过 将具有不变性的数据作为属性传递给我们的应用程序。

现在我们回到前面的代码片段来重新想象我们应用程序的组件结构,可以用下面这张图来表示:

如上,我们可以使用===来通过引用来比较对象,这意味着我们能够方便快速的进行对象比较,并且它能够和React中的PureRenderMixin 兼容。基于此,我们可以在整个应用构建中使用Immutable.js。也就是说,我们的Flux Store应该是一个具有不变性的对象,并且我们通过 将具有不变性的数据作为属性传递给我们的应用程序。

现在我们回到前面的代码片段来重新想象我们应用程序的组件结构,可以用下面这张图来表示:

如上,我们可以使用===来通过引用来比较对象,这意味着我们能够方便快速的进行对象比较,并且它能够和React中的PureRenderMixin 兼容。基于此,我们可以在整个应用构建中使用Immutable.js。也就是说,我们的Flux Store应该是一个具有不变性的对象,并且我们通过 将具有不变性的数据作为属性传递给我们的应用程序。

现在我们回到前面的代码片段来重新想象我们应用程序的组件结构,可以用下面这张图来表示:

var stateV1 = Immutable.fromJS({    users: [    { name: 'Foo' },    { name: 'Bar' }  ]});var stateV2 = stateV1.updateIn(['users', 1], function () {    return Immutable.fromJS({    name: 'Barbar'  });});stateV1 === stateV2; // false  stateV1.getIn(['users', 0]) === stateV2.getIn(['users', 0]); // true  stateV1.getIn(['users', 1]) === stateV2.getIn(['users', 1]); // false  

如上,我们可以使用===来通过引用比较对象,这意味着我们能够方便快速地进行对象比较,并且它能够和React中的PureRenderMixin 兼容。基于此,我们可以在整个应用构建中使用Immutable.js。也就是说,我们的Flux Store应该是一个具有不变性的对象,并且我们通过将具有不变性的数据作为属性传递给我们的应用程序。

现在我们回到前面的代码片段来重新想象我们应用程序的组件结构,可以用下面这张图来表示:


从上面的图形中你可以发现,在应用状态发生变化后,只有红色的部分会被重新渲染,因为其他部分的引用数据并没有发生变化。也就是说, 只有根组件和其中一部分的user组件会被重新渲染。

基于这种不变性,能够优化React组件的渲染路径,并通过这种方式来重新思考我们的应用构建和应用性能优化。此外,得益于虚拟DOM, 它能够让React应用比传统应用来得更加高效与快速。(责编:陈秋歌)

译者简介:景庄,前端工程师,关注Node.js、前端工程化。个人博客:http://wwsun.github.com。


欢迎加入CSDN前端交流群2:465281214,进行前端技术交流。  

也可参加CSDN前端大讲堂(微信公开课),享受高含金量在线公开课,与专家讲师在线切磋交流。

如何加入CSDN前端大讲堂?由于该群目前已超过人数限制,所以您首先不得不 扫描下面二维码,加CSDN编辑陈秋歌为好友,然后请她邀请您加入CSDN前端大讲堂微信群。加好友时,请务必注明“申请加入CSDN前端大讲堂”。


世界上最高深的Android特洛伊病毒 招聘iOS开发,老板必问的5个问题 护航科技吴伟湘:IT离线安全体检服务将带来颠覆 百度王继平:移动互联网时代云平台思路 “第八届开源中国开源世界高峰论坛”火热开启 微软发布SQL Server 2014预览版,展示内存数据库技术 帮助软件开发者提高效率的10个小窍门 我想做个程序员:Technovation Challenge圆女孩编程梦想 未来我们开发的Google Glass应用将会是什么样? 独家:前RIM大中华区总经理刘征宇,加入Appconomy 用一个API搞定一切 Segment.io为移动开发者提供便利的分析数据分发服务 TIOBE 6月编程语言排行榜:JavaScript回归前十 《Kingdom Rush Frontiers》上线后 迅速抢占27个国家游戏榜首 移动周报:85后程序员,iOS开源项目,细数7天大事件! Instagram:从Redis到Cassandra 成本节省1/4 乐元素CTO凌聪访谈:游戏引擎技术选型之王道 iOS 7的新设计并非止于外表 WWDC 2013大会10大启示:正向开发者支付大量现金 云计算大会微软专场成功举办 Windows Azure公众预览版上线 IBM全球大裁员 在美国裁员已经开始 动动鼠标,决定“中国十大优秀开源项目”的归属 为改善Flickr 雅虎收购拍照应用开发商GhostBird 让你轻松学习新代码库的六个步骤 RESTful API 设计最佳实践 谷歌11亿美元豪购Waze原因:获取数据 争本地广告市场 为什么大家都要疯狂吐槽iOS 7的扁平化设计? 伟大的程序员是天生的,不是造就的 比Hive高效7倍 Facebook推新一代查询引擎Presto 未来的存储系统设计——PMC技术交流会举行 第五届中国云计算大会PPT尝鲜:十位专家分享的架构实践 “DIY”可穿戴设备:索尼开放智能手表固件 关于 delphi的一点东东 access一个日期时间字段是短格式的,用什么SQL语句改成长格式的? 怎样才能在主页中显示自己的qq是否在线?????? 有没有平面按钮控件 Interdev6.0 IDE 环境下无法使用MSDN access一个日期时间字段是短格式的,用什么SQL语句改成长格式的?? 大家来帮帮我想想?应该怎么样来删除呢!!!! 各位用VB.net的兄弟,请问你们使得是 Beta1 还是 Beta2 ? 迷周星弛的请来签名啊! 如何操纵RichTextEdit控件??? 我得到GIF图像的这一点的值,怎样得到它的正确的RGB值? 我想请问在CHTML(compact html)中如何对页面进行刷新。 各位老大,你们是如何找到工作的? 在VB.net中,如何实现VB6中的 set A=createobject("XXXX.XXXX") 诸位大虾救命,如何在EDIT控件中判断DBCS字符 !!求救!!对时!!! 在VC中使用Crystal report 8的问题 如何编写c程序自动对GIF图片设置大小 请教:鼠标在windows桌面上按键是否会引发某个事件? 查看DLL的输出函数 menu的问题 web的组件由什么来编写? 嵌入式数据窗口,怎样可以动态往里插数据窗口??? 在DELPHI中如何调用NETBIOS的API函数 AddNew 怎么用?- 怎么办那,啊? 问题标题前的绿色的对号是什么意思?是不是表示问题已经解决? 怎么学VC啊,菜鸟的菜菜的问题啊。 关于打印比较 提取汉字的拼音 四级挂了,给分,气死了 难题时时有,把它问诸位,不知哪位高手,今日肯帮俺------解决送个人照片(不知各位肯要否?) 刚考完英语四级,来这里发泄一下。同时送上300分! PHP和JAVA如何通讯? 请问哪里有 soft-ice for 2k 如何将字符串的首尾空格去掉??? 1分钟求解:与HEX()对应的把16进制转换成10进制的函数是什么? 怎样判断某个控件是button、edit还是combox、listctrl......? VB.NET(VS.NET)/Beta2正式版下载地址与安装方法 有人用VsPrint吗? delphi、vc、c++ builder三者,哪一种是你的最终选择,why? 第一次上来灌,宋粉 关于C编译后的几个文件后缀名. 请教各位,主要用于办公和工程预决算,用AMD的Duron+km133(集成savage4)行吗? delphi、c++ builder、vc三者,哪一种是你的最终选择,why? 程序结束时,窗体和内存的释放问题 c++ builder、delphi、vc三者,哪一种是你的最终选择,why? 唉,牙齿好疼 高分求语音系统算法! 你认真思考过你的共享软件为什么赚不了钱吗? 请问在那里可以找到ratioal2001的破解 关于x的方程4x-a²x=2-a有无数解那么a=? 若方程组3x+y=1+3a,x+3y=1-a的解满足x+y=0,求a的取值 已知二次方程3x²-(2a-5)x-3a-1=0有一个根为2,求另一个根拜托各位了 3Q x-5分之2+4分之一等于八分之五,方程怎么解? a若方程组{3x+y=1+3a x+3y=1-a的解满足x+y>0,则a的取值范围是( ) 已知x的平方加3x-1=0求x的平方+x的负二次方 八分之七x等于六分之一乘八分之五 已知方程组3x-4y=3a-6,x+3y=2a+7的解x,y都是正数,且x的值大于y的值,求a的取值范围 已知关于x的二次方程x^2-(k-1)x-3x-2=0的两个实数根的平方和为17,求k的值已知a,b分别满足a^2-2ma-m^2=0和b^2-2mb-m^2=0,则b/a+a/b的值是多少? X*8%+(60-X)*9%=5 求解这个方程 得数等于40 已知2x+3y=a+2,且3x-4y=3a-1,若XY =0,求a的取值范围 .不是xy=0。应该是xy>=0。 a为何值时,方程2x+1/3a=x-1的解满足2x+3=7?a为何值时,方程2x+1/3a=x-1的解满足2x+3=7?5点之前,帮帮啊 (x+2+x)×5÷2=40 这个方程怎么算 方程4(3-2x)+3a+2=7-4a-3(x-5)的解不比2a+1小,求a的取值范围 已知关于x的方程2x-3a=1的解是x-3,那么a的值是 方程 1+40%x=4分之5(要过程) 已知关于x的方程4(3-2x)+3a+2=7-4a-3(x-5)的解不小于2a+1,求a的取值范围kkkkk 已知关于x的方程x-4/2-2x-3a/5=1和2a+x/4-x-2/3=1有相同的解,则解是 X的2倍与9的和等于-3,方程是 已知关于X的方程4(3—2X)+3a+1=5—4a+3(X—5)的解不比2a—1小,求a的取值范围? 已知方程2x+3a=4 与3x+5=2的解相同 a= 十x-3等于9方程式求解答 已知方程4(3-2x)+3a+2=7-4a-3(x-5)的解不比2a+1小,求a的取值范围 关于x的方程5x-3a=2x-7的解是负数,试求a的取值范围. 一个数的二分之一比这个数的25%多10.这个数是多少?方程解 已知关于X的方程3a+x=a\2x+3的解为x=4,求a-2a+3a-4a+5a-6a+ +99a-100a的值 如果关于x的方程5x+3a=2x-7的解是负数,试求a额取值范围 根据下列条件列出方程:一个数的5倍比这个数大10;一个数的5倍与9的差等于这个数的一半;某数比它的7倍小2一个数与4的和的3倍比这个数大5 已知关于x的方程4(x+2)-2=5+3a的解不小于方程(3a+1)/3=a(2x+3)/2的解,求a的取值范围. 如果代数式关于x的方程5x-3a=2x-7的解是负数,试求a的取值范围我算出来是a<3分之10 10分之3和5分之1的和等于一个数的4分之3,求这个数.(用方程解) 写题即可计划产量:实际产量:24吨(比计划增产3分之1)甲,乙,丙各有若干张邮票,甲的邮票是乙的3分之2,乙的邮票是丙的4分 已知关于x的方程3(x+2)-2=7+3a的值不大于(5a+1)/5 x=(2x+3)a/2的解,求a的取值范围 解方程 (x+0.8)÷6=7.2 求方程的解 10/9X-66=6/1X 这个方程怎么解? 已知关于x的方程ax^2-(2a+1)x+3-3a=0的解都大于1,则a的取值范围是答案是0≤a<0.5老师是用△≥0,韦达定理做的 2号答对x道,10x-(8-x)*6=64,x=7; 方程 怎么解 x-5/1x=10/7这个方程式怎么解 如果关于x的方程3(x+4)-4=2a+1的解大于方程4a+1/4 x=a(3x-4)/3的解,求a 的取值范围 6,7,8三题,用方程解 已知方程4x-3m=x-6m+1的解在1和负1之间则满足条件的整数值为( ) 顺便分析下 方程10.1X加38.6=54.3加9.55怎么解 已知关于x的方程:4(x+2)-2=5+3a的解不小于方程(3a+1)x/3=a(2x+3)/2的解,求a的取值范围. 若方程X^2-4X+3M=0,与X^2-X-6M=0有一个根相同,求M 3分之2x÷5分之3=15 解方程 x+4分之1x=7.5 已知方程2/3x-3k=5(x-k)+1的解为非负数,求k的取值范围 已知关于x的方程4x-3m=2的解x=m,则m的值是 若关于x的方程x+2=a和2x-a=3a有相同的解,求a(1/2)某学校在援助边远山区活动中,原计划捐书3000册,由于学生的积极响应,实际捐书3780册,其中初中部比原计划多捐了20%.高中部比原计(2/2)划多捐 关于x的方程2/3x=5(x-k)+3k+1的解是负数,求k的取值范围. 已知关于x的方程4x-3m=2的解是x=m,则m的值是 关于x的方程2x-3a=1的解是x=a,则a=? 已知关于X·y的方程组2x+y=2k+1 3x-2y=k-1的解满足x-3y<5求k的取值范围 怎么算 已知关于x的方程4x-3m=2的解是x=-m,则m的值为( ). 诺关于X的方程x+2=A和2X-4=3A有相同的解,则A=?急 当K为何值时,方程组3x-y=2k和x+2y=3k-14的X、Y互为相反数? 方程5(x-1)²+4x=0 求b²-4ac 已知方程组2x-3y=2-3a,3x-4y=2a-1的解满足x>0,y 已知关于x,y的方程组 2x+y=2k+1,3x-2y=3k-9的解满足x小于y,求k的范围. 方程x²+4x+1=0的根是 已知方程组{2x-4y=2-3a 3x-4y=2a+1 的解满足{x>0 y 已知二次方程3x²-(2a-5)x-3a-1=0有一个根为x=2,求另一个根并确定a的值
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn