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

探索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前端大讲堂”。


采集颜色、自动同步,还有比这更牛叉的儿童触控笔么? AppCan移动平台:为企业移动化进程加速 学生强则国强,访天猫推荐算法大赛Top 9团队 Mozilla与三星之子——Servo特性解读 360天巡启动公测 打造新一代企业级无线安全解决方案 继Storm和Spark之后,Hortonworks添加对Kafka的支持 一周消息树:国产操作系统最快10月发布,并支持应用商店 技术团队看板方法实践的难点分析 SAP云服务加速转型:调动资源瞄准中国市场 开发测试全承包!移动应用开发工具Telerik平台 火火火火火!看HomeKit如何改变物联网和智能家居? MDCC应用与工具关键词:平台、社交、垂直、解决方案 Leap Motion正式入华 将发布第二代软件SDK 120万操作/秒Redis Cloud 集群单一服务器非基准测试程序 2014微信开发者大会顺利结束 TOP10优秀微信开发商名单公布 【最佳实践】通过DevOps确保可靠和有效的信息安全 2048 Hello World:跨平台快速应用开发Python框架Kivy Forrester:关于私有云的10个事实 2014年8月操作系统份额:Win 8.x大涨,Linux继续下跌 0代码、不编程—交互式网页设计工具VXPLO 揭秘Instagram Hyperlapse背后的技术 【CTO俱乐部在线教育研讨会】用互联网技术深入创新教育产品 降低门槛!Hybrid应用开发框架LigerMobile 下一代IT革命:微服务器和雾计算 使用Mongo Connector和Elasticsearch实现模糊匹配 时隔8个月,物联网联盟AllSeen如今怎样? 《近匠》简网:开发零门槛 快速建原生App MDCC免费展位申请超预期 大会内容初曝光 在服务器与交换机定制之后,谷歌着手量子计算机CPU设计 电信天翼开放平台鲍占斌:优质能力 分成比例高 艾格拉斯副总裁王晓波:手游定价如何设计 如何在ie中直接打开word文件进行浏览、编辑,并保存。 一直都在接分,我也散点分。祝大家中秋快乐!!!!!! 我学应用物理,计算机该怎么自学?100+100=200 大分相送!不够再加(第1部) 有一个问题,怎么配置struts,有没有一个现成的例子呀,望指点,谢谢,也可以发到我的信箱 有CSDN上的兄弟一起过中秋节晚上,今晚不孤独,最后七十分散掉 oracle9i...数据库是提示:ORA-12154: TNS: 无法处理服务名 ? **首先祝大家中秋快乐,然后请问“包程序写入失败”是什么意思???**谢谢:-) 我学应用物理,计算机该怎么自学?100+100=200 大分相送!不够再加(第2部) 如何將數組定義在一段連續的內存空間??急急!!!!! **首先祝大家中秋快乐,然后请问“包程序写入失败”是什么意思???**谢谢:-) 我用这个函数Space$(nSize),提示说工程库没有,需要什么工程库? 两罐啤酒,独过中秋。祝这里的兄弟姐妹中秋快乐! 一个有关datareport的问题 现在有必要学ASP吗? 请教:为什么我不能给被调用包的源代码设置断点,请问是什么原因?怎么解决? 补刚才漏掉的五十分 想编写一个新邮件到达时自动通知的程序,请提供思路 关于SAX对大数据量文件的读写(高分) 中秋节编的程序是不是特别好吃? 请问:什么是“C runtime 函式庫的 Startup code”呢?? 关于自动播放的问题,在线等! 关于自动播放的问题,在线等! 请问怎么读取 text 控件 中 任意一行的内容 如何用jad?谢谢 哪儿有bc++高一点的版本下载 dbf问题 中秋了,我写了一首诗,大家看写得精彩不精彩? 我学应用物理,计算机该怎么自学?100+100=200 大分相送!不够再加(第3部) 和众马甲共度中秋,来来来,吃月饼,吃月饼 请问光驱读盘效率不高会是什么原因? 帮帮忙啊,关于图的遍历 一个form上有两个dbgrid,怎么判断我现在的焦点是在哪个 dbgrid上? 送给8。15继续在网络中漫步的朋友们的礼物! 关于数据库的使用 一个有关listview的问题,一直没解决,急! 有没有人装过MINIX啊 为什么我在查询分析器里执行时,没有时间限制,而在控制台里用同样的代码建一个试图或写在存储过程里都会超时呢········· 中秋快乐!!!!!!!!!大家进来看看,小弟有些问题。 网站运行一会儿IIS自动不运行了 什么是SCSI卡设备呢?有何作用? 未来的软件架构和技术 哪里有VB好界面下啊,谢谢 推荐给希望了解应用程序开发全过程的“初学者”一本书!!!!!!!!! 过节了!谨以些分献给坚守在灌水第一线的朋友们~~(一) 未来的软件架构和技术 zalyer接帖 过节了!谨以些分献给坚守在灌水第一线的朋友们~~(二) 数据库保存图片的问题 js赋值后提交,怎么在servlet中value 为空?? SendMessage参数问题, 过节了!谨以些分献给坚守在灌水第一线的朋友们~(三) 天高任鸟飞(后一句是:海阔?鱼?) 海阔凭鱼跳下一句,和春潮带雨晚来急下一句 请问“天高任鸟飞”和“海阔凭鱼越”这两句哪句在前面? 跪求一篇英语作文 :“假如你是英语俱乐部的成员,你的朋友兰芳也想加入.你需要帮她写一封推荐信 70词左右姓名:兰芳生日:1999-6-7爱好:旅游,看英语电影申请理由:喜欢英语,梦想有一天 请问明代山东青州府乐安县张家庄是现在广饶县的哪个村?我们始祖在明朝万历年间从那儿迁出的我主要是想知道张家庄是现在的哪个村 请问山东省青州府乐安县倒庄街现在叫什么名字 在什么地方啊看到族谱 是从山东省青州府乐安县倒庄街迁到山东德州的 现在这个地方叫什么名字了 青州府乐安县碑次口村现在在什么地方? 原青州府乐安县贾家楼有哪位知道 青州府乐安县耿家庄现为何地?姓王,原为兵部侍郎,后贬职到四川省广元市 古代的著名隐者有哪些? 告诫人们不要死读书的名言, 淡水河谷40年累计向中国出口铁矿石1安倍希望早日通过新设“国家安全保障会加拿大总督访问蒙古国李克强同蒙古国总理阿勒坦呼亚格举行会上合组织就打击恐怖主义召开研讨会佟屏亚:转基因作物能增产是骗人的!浙江一男子利用感光材料提炼白银污染环商贾云集浙江觅得知音 杭州揽投资15西班牙首相拉霍伊:将就监控事件召见美西班牙首相拉霍伊:将就监控事件召见美尼日利亚海盗绑架美船员 西非海域险过郭声琨会见土库曼斯坦国家安全部部长打砸肇事者须自首涉三千万假冒伪劣油漆流向多地深圳警方冒雨开展处突模拟训练浙江省司法行政系统掀起学习贯彻习近平原原本本传达学习深刻领会精神实质净身出户保证有效企业老总“借钱”还贷涉嫌诈骗上亿元坚决把暴力恐怖活动摧毁在预谋阶段新疆严打遏制暴恐音视频传播蔓延标题新闻撒旦危情:大亨的豪门叛妻蚁贼我的教练是死神夜墓之谜宝山塔魔流星太空战士英雄嗔惟武独尊大儒介休旅游澎湖旅游白银旅游弥勒旅游驻马店旅游青藏线旅游蔚县旅游斗门旅游屏东旅游莱芜旅游和田旅游
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘