ReactJS组件之间如何进行通信

最近在学习react.js,不得不说第一次接触组件化开发很神奇,当然也很不习惯。

react的思想还是蛮独特的,当然围绕react的一系列自动化工具也是让我感觉亚历山大

今天总结一下react组件之间的通信,权当是自己的学习笔记:

reactJs中数据流向的的特点是:单项数据流

react组件之间的组合不知道为什么给我一种数据结构当中树的感觉,数据就是从根节点(顶端或其他子树的顶端)“流”下来,大概就是这个样子:

比如这是一个组件树,数据就可以从main组件流到jumbotron组件、queationList组件、form组件,类似的queation组件的数据也可以流到下边的question组件里边。

但是很遗憾,这个从上到下的数据流动,只能解决很少的问题,还有一部分的数据流动就是类似从jumbotron组件到form组件的这样的兄弟组件的流动形式,或者隔着几个层级的数据流动,再或者子组件发生了数据的变化,想通知父组件,数据流向从子组件到父组件流,这些问题才是大多数的开发者需要面临的问题。所以这篇笔记总结下基础的组件通信:

数据从父组件到子组件

最简单的通信就是父子间的通信,比如上边图上的有个jsonObj从main流进了QueationList参考代码:


  1. //这里模拟出几条数据 
  2. var jsonObj=[ 
  3.     {name:"A",question:"从小被人打怎么办?",TextArea:"习惯就好了",applaud:35,disagree:1}, 
  4.     {name:"B",question:"长的太帅被人砍怎么办?",TextArea:"食屎啦你",applaud:35,disagree:10}, 
  5.     {name:"C",question:"因为太胖被人摸怎么办?",TextArea:"享受就好了",applaud:35,disagree:45}, 
  6.     {name:"D",question:"被老师打不开心",TextArea:"用钱打脸",applaud:35,disagree:6}, 
  7.     {name:"E",question:"不爱洗澡怎么办?",TextArea:"打一顿就好了",applaud:35,disagree:9} 
  8.  
  9. var QuestionList=React.createClass({ 
  10.     prepareToRender:function(list){ 
  11.         var array=[]; 
  12.         for(var i=0;i<list.length;i++){ 
  13.             array.push(<Question obj={list[i]}   key={i}/>); 
  14.         } 
  15.         return array; 
  16.     }, 
  17.     render:function(){ 
  18.         var array=this.prepareToRender(this.props.jsonObj); 
  19.         return <div>{array}</div>; 
  20.     } 
  21. }); 
  22. var Main = React.createClass({ 
  23.     //开始渲染 
  24.     render: function () { 
  25.         return ( 
  26.             <div> 
  27.                 <div className="container col-md-6 col-md-offset-3"> 
  28.                     <div className="container-fluid"> 
  29.                         <QuestionList jsonObj={jsonObj}  /> 
  30.                     </div> 
  31.             </div> 
  32.         ); 
  33.     } 
  34. }); 
  35. ReactDOM.render( 
  36.     <Main />, 
  37.     document.getElementById('container') 
  38. );  

代码写的不怎么规范,但是数据的传递就是这样的:

<QuestionList jsonObj={jsonObj} />

这样就可以把父组件的数据带到子组件里边

数据从子组件到父组件

理论上来说数据只能是单向的,所以不借助插件数据还真不好从子组件到父组件,一种很简单的手段是回调函数:

在父组件当中写个回调函数,然后传递到子组件,什么时候子组件数据变化了,直接调这个回调函数就可以了。

比如现在的jumbotron的按钮被点击了,我们想把被点击这个事件发给它的父组件也就是main组件,那么我们可以这个做:


  1. var Jumbotron = React.createClass({ 
  2.     handleClick: function () { 
  3.         this.props.openTheWindow(false); 
  4.     }, 
  5.     render: function () { 
  6.         return ( 
  7.                 <div className="row"> 
  8.                     <div className="col-md-6  col-md-offset-3"> 
  9.                         <button type="button" className="btn btn-default btn-lg" onClick={this.handleClick}>开始体验 
  10.                         </button> 
  11.                     </div> 
  12.                 </div> 
  13.             </div> 
  14.         ); 
  15.     } 
  16. }); 
  17.  
  18. var Main = React.createClass({ 
  19.     getInitialState: function () { 
  20.         return { 
  21.             openTheWindow: true 
  22.         }; 
  23.     }, 
  24.     //开始给子组件一个回调函数,用来做子组件给父组件通信使用 
  25.     buttonResponse:function(windowSatus){ 
  26.         this.setState({openTheWindow : windowSatus}); 
  27.     }, 
  28.     //开始渲染 
  29.     render: function () { 
  30.         console.log(jsonObj) 
  31.         return ( 
  32.             <div> 
  33.                 <Jumbotron openTheWindow={this.buttonResponse}/> 
  34.             </div> 
  35.         ); 
  36.     } 
  37. }); 
  38. ReactDOM.render( 
  39.     <Main />, 
  40.     document.getElementById('container') 
  41. );  

子组件通知父组件状态变化就是这样,就好像是儿子找爸爸要零花钱,零花钱以及给不给都是爸爸说了算的。

兄弟组件之间的通信

这个其实应该是一个动态应用中最常见的通信,比如jubotron组件的点击按钮,form组件的表单出现:

这就是一个典型的兄弟之间的通信:

兄弟节点其实可以就是子父通信&&父子通信的叠加

首先按钮被点击,子组件通知负组件这个事件,然后父组件把这个消息带给另一个子组件

下边是个点击按钮显示表单的例子:


  1. /** 
  2.  * Created by niuGuangzhe on 2016/9/10. 
  3.  */ 
  4. var Jumbotron = React.createClass({ 
  5.     handleClick: function () { 
  6.         this.props.openTheWindow(false); 
  7.     }, 
  8.     render: function () { 
  9.         return ( 
  10.             <div className="jumbotron"> 
  11.                 <div className="row"> 
  12.                     <div className="col-md-6  col-md-offset-3"> 
  13.                         <button type="button" className="btn btn-default btn-lg" onClick={this.handleClick}>开始体验 
  14.                         </button> 
  15.                     </div> 
  16.                 </div> 
  17.             </div> 
  18.         ); 
  19.     } 
  20. }); 
  21.  
  22. var Form = React.createClass({ 
  23.     getInitialState:function(){ 
  24.         return { 
  25.             inputTitle:"请输入标题", 
  26.             mainBody:"在此输入正文" 
  27.         }; 
  28.     }, 
  29.     //点击按钮触发事件:清除所有已经输入的文字 
  30.     cleanText:function(){ 
  31.         this.setState({ 
  32.             inputTitle:"", 
  33.             mainBody:""}); 
  34.     }, 
  35.     //表单监视事件 
  36.     handleChange(name,e) { 
  37.         var newState = {}; 
  38.         console.log(name); 
  39.         newState[name] =event.target.value; 
  40.         this.setState(newState); 
  41.     }, 
  42.     render: function () { 
  43.         return ( 
  44.             <div style={{display:this.props.openTheWindow?"none":"block"}}> 
  45.                 <form role="form"> 
  46.                     <div className="form-group"> 
  47.                         <label htmlFor="title">标题</label> 
  48.                         <input type="text" className="form-control" id="title" name="inputTitle" value={this.state.inputTitle} onChange={this.handleChange.bind(this,"inputTitle")}/> 
  49.                     </div> 
  50.  
  51.                     <div className="form-group"> 
  52.                         <label htmlFor="textArea">正文</label> 
  53.                         <textarea className="form-control" rows="3" id="textArea" name="mainBody" value={this.state.mainBody} onChange={this.handleChange.bind(this,"mainBody")}></textarea> 
  54.                     </div> 
  55.                     <div className="row"> 
  56.  
  57.                         <input type="button" className="btn btn-default pull-right leaveMeAlone" value="取消"  onClick={this.cleanText}/> 
  58.                         <input type="submit" className="btn btn-primary pull-right leaveMeAlone" value="提交"/> 
  59.                     </div> 
  60.                 </form> 
  61.             </div> 
  62.         ) 
  63.     } 
  64. }) 
  65.  
  66.  
  67. var Main = React.createClass({ 
  68.     getInitialState: function () { 
  69.         return { 
  70.             openTheWindow: true 
  71.         }; 
  72.     }, 
  73.     //开始给子组件一个回调函数,用来做子组件给父组件通信使用 
  74.     buttonResponse:function(windowSatus){ 
  75.         this.setState({openTheWindow : windowSatus}); 
  76.     }, 
  77.     //开始渲染 
  78.     render: function () { 
  79.         console.log(jsonObj) 
  80.         return ( 
  81.             <div> 
  82.                 <Jumbotron openTheWindow={this.buttonResponse}/> 
  83.                 <div className="container col-md-6 col-md-offset-3"> 
  84.                     <Form openTheWindow={this.state.openTheWindow}/> 
  85.                 </div> 
  86.             </div> 
  87.         ); 
  88.     } 
  89. }); 
  90. ReactDOM.render( 
  91.     <Main />, 
  92.     document.getElementById('container') 
  93. );  

就是这样,

其实上边的代码是我从之前的没事干做的一个单页面上拿过来改的,为了不出现代码无法运行的问题,下边贴出所有代码:


  1. /** 
  2.  * Created by niuGuangzhe on 2016/9/10. 
  3.  */ 
  4. var Jumbotron = React.createClass({ 
  5.     handleClick: function () { 
  6.         this.props.openTheWindow(false); 
  7.     }, 
  8.     render: function () { 
  9.         return ( 
  10.             <div className="jumbotron"> 
  11.                 <div className="row"> 
  12.                     <div className="col-md-6  col-md-offset-3"> 
  13.                         <h2 className="colorChange">React+bootstrap简单实例</h2> 
  14.                     </div> 
  15.                 </div> 
  16.                 <div className="row"> 
  17.                     <div className="col-md-6  col-md-offset-3"> 
  18.                         <p className="colorChange">上手体验:第一次尝试组件化开发</p> 
  19.                     </div> 
  20.                 </div> 
  21.                 <div className="row"> 
  22.                     <div className="col-md-6  col-md-offset-3"> 
  23.                         <button type="button" className="btn btn-default btn-lg" onClick={this.handleClick}>开始体验 
  24.                         </button> 
  25.                     </div> 
  26.                 </div> 
  27.             </div> 
  28.         ); 
  29.     } 
  30. }); 
  31.  
  32. var Form = React.createClass({ 
  33.     getInitialState:function(){ 
  34.         return { 
  35.             inputTitle:"请输入标题", 
  36.             mainBody:"在此输入正文" 
  37.         }; 
  38.     }, 
  39.     //点击按钮触发事件:清除所有已经输入的文字 
  40.     cleanText:function(){ 
  41.         this.setState({ 
  42.             inputTitle:"", 
  43.             mainBody:""}); 
  44.     }, 
  45.     //表单监视事件 
  46.     handleChange(name,e) { 
  47.         var newState = {}; 
  48.         console.log(name); 
  49.         newState[name] =event.target.value; 
  50.         this.setState(newState); 
  51.     }, 
  52.     render: function () { 
  53.         return ( 
  54.             <div style={{display:this.props.openTheWindow?"none":"block"}}> 
  55.                 <form role="form"> 
  56.                     <div className="form-group"> 
  57.                         <label htmlFor="title">标题</label> 
  58.                         <input type="text" className="form-control" id="title" name="inputTitle" value={this.state.inputTitle} onChange={this.handleChange.bind(this,"inputTitle")}/> 
  59.                     </div> 
  60.  
  61.                     <div className="form-group"> 
  62.                         <label htmlFor="textArea">标题</label> 
  63.                         <textarea className="form-control" rows="3" id="textArea" name="mainBody" value={this.state.mainBody} onChange={this.handleChange.bind(this,"mainBody")}></textarea> 
  64.                     </div> 
  65.                     <div className="row"> 
  66.  
  67.                         <input type="button" className="btn btn-default pull-right leaveMeAlone" value="取消"  onClick={this.cleanText}/> 
  68.                         <input type="submit" className="btn btn-primary pull-right leaveMeAlone" value="提交"/> 
  69.                     </div> 
  70.                 </form> 
  71.             </div> 
  72.         ) 
  73.     }, 
  74.     //监测从新渲染 
  75.     componentDidUpdate:function(){ 
  76.         console.log("子组件重新渲染;"); 
  77.     } 
  78. }) 
  79.  
  80. var Question = React.createClass({ 
  81.     getInitialState : function(){ 
  82.         return { 
  83.             click:true, 
  84.             disClick:true 
  85.         }; 
  86.     }, 
  87.     numberHandle:function(){ 
  88.         if(this.state.click===true){ 
  89.             //奇数次点击,开始增加数据 
  90.             this.props.obj.applaud+=1; 
  91.             this.setState({click:false}); 
  92.         }else{ 
  93.             //偶数次点击,减去数据 
  94.             this.props.obj.applaud-=1; 
  95.             this.setState({click:true}); 
  96.         } 
  97.     }, 
  98.     decreateHandle:function(){ 
  99.         if(this.state.disClick===true){ 
  100.             //奇数次点击,开始增加数据 
  101.             this.props.obj.applaud-=1; 
  102.             this.setState({disClick:false}); 
  103.         }else{ 
  104.             //偶数次点击,减去数据 
  105.             this.props.obj.applaud+=1; 
  106.             this.setState({disClick:true}); 
  107.         } 
  108.     }, 
  109.     render: function () { 
  110.         return ( 
  111.             <div className="row leaveMe"> 
  112.                 <div className="col-md-2"> 
  113.                     <div className="col-md-12"> 
  114.                         <button className="btn col-md-12 " onClick={this.numberHandle}>{this.props.obj.applaud-this.props.obj.disagree}<br/><span 
  115.                             className="glyphicon glyphicon-chevron-up"></span></button> 
  116.                     </div> 
  117.                     <span>&ensp;</span> 
  118.                     <div className="col-md-12"> 
  119.                         <button className="btn col-md-12" onClick={this.decreateHandle}><span 
  120.                             className="glyphicon glyphicon-chevron-down"></span> 
  121.                         </button> 
  122.                     </div> 
  123.                 </div> 
  124.                 <div className="col-md-10  bs-callout bs-callout-info"> 
  125.                     <h4>{this.props.obj.question}</h4> 
  126.                     <p>{this.props.obj.TextArea}</p> 
  127.                 </div> 
  128.             </div> 
  129.         ); 
  130.     } 
  131. }); 
  132.  
  133. var QuestionList=React.createClass({ 
  134.     prepareToRender:function(list){ 
  135.         var array=[]; 
  136.         for(var i=0;i<list.length;i++){ 
  137.             array.push(<Question obj={list[i]}   key={i}/>); 
  138.         } 
  139.         return array; 
  140.     }, 
  141.     render:function(){ 
  142.         var array=this.prepareToRender(this.props.jsonObj); 
  143.         return <div>{array}</div>; 
  144.     } 
  145. }); 
  146.  
  147.  
  148. //这里模拟出几条数据 
  149. var jsonObj=[ 
  150.     {name:"A",question:"从小被人打怎么办?",TextArea:"习惯就好了",applaud:35,disagree:1}, 
  151.     {name:"B",question:"长的太帅被人砍怎么办?",TextArea:"食屎啦你",applaud:35,disagree:10}, 
  152.     {name:"C",question:"因为太胖被人摸奶怎么办?",TextArea:"享受就好了",applaud:35,disagree:45}, 
  153.     {name:"D",question:"被老师打不开心",TextArea:"用钱打ta脸",applaud:35,disagree:6}, 
  154.     {name:"E",question:"不爱洗澡怎么办?",TextArea:"打一顿就好了",applaud:35,disagree:9} 
  155.  
  156. var Main = React.createClass({ 
  157.     getInitialState: function () { 
  158.         return { 
  159.             openTheWindow: true 
  160.         }; 
  161.     }, 
  162.     //开始给子组件一个回调函数,用来做子组件给父组件通信使用 
  163.     buttonResponse:function(windowSatus){ 
  164.         this.setState({openTheWindow : windowSatus}); 
  165.     }, 
  166.     //开始渲染 
  167.     render: function () { 
  168.         console.log(jsonObj) 
  169.         return ( 
  170.             <div> 
  171.                 <Jumbotron openTheWindow={this.buttonResponse}/> 
  172.                 <div className="container col-md-6 col-md-offset-3"> 
  173.                     <Form openTheWindow={this.state.openTheWindow}/> 
  174.                     <br/><br/> 
  175.                     <div className="container-fluid"> 
  176.                         <QuestionList jsonObj={jsonObj}  /> 
  177.                     </div> 
  178.                 </div> 
  179.             </div> 
  180.         ); 
  181.     }, 
  182. //    执行hook函数:重新渲染完成的时候调这个函数 
  183.     componentDidUpdate:function(){ 
  184.         console.log(this.state.openTheWindow); 
  185.     } 
  186. }); 
  187. ReactDOM.render( 
  188.     <Main />, 
  189.     document.getElementById('container') 
  190. );  

最后就是一个很重要的问题:就是多层级的据数据传输,如果还用这个方式来传播的话,效率貌似是个大问题,解决办法看大家的做法目前暂时还是flux之类的其他框架,等研究出来单独写篇文章吧

作者:易燃易爆炸

来源:51CTO

时间: 2024-08-08 00:15:15

ReactJS组件之间如何进行通信的相关文章

发送-delphi tcpserver 和tcpclient之间怎么互相通信

问题描述 delphi tcpserver 和tcpclient之间怎么互相通信 只写出了tcpclient向tcpserver发送消息 ,请大神 指导一下tcpserver 怎么向tcpclient 发送消息 解决方案 从服务器返回数据 如果需要从服务器返回数据的话,只需要在OnAccept中调用ClientSocket.Sendln方法即可.客户端需要做的就是在执行完TcpClient1.Sendln后,直接调用 TcpClient1.Receiveln即可.该方法会等待服务器传回的信息.当

.NET组件和COM组件之间的相互操作

.NET组件和COM组件之间的相互操作.NET技术是微软大力推广的下一代平台技术,自从.NET技术架构Beta2版本的正式发布,此项技术也逐渐走向成熟和稳定.按照微软的平台系统占有率,我们不难想象得到,在未来的一两年内.NET技术必定会势如破竹一般的登上主流的技术平台,而一个新的技术平台得以快速发展的最重要的前提是:他不会彻底的摒弃以前的技术,这一点对于.NET技术来说指的就是COM/COM+技术了. 一般来说,在IT技术界以及硬件产业,技术的更新换代速度非常得惊人,而惯例是所有的新技术都会遵循

简述在Java Web组件之间的三种关联关系

在Java Web组件之间的三种关联关系: 1.请求转发 2.URL重定向 3.包含 请求转发: 允许把请求转发给同一应用程序中的其他web组件. 这种技术通常用于web应用控制层的servlet流程控制器,它检查http请求数据,并将请求转发到适合的目标组件,目标组建执行具体的请求处理操作,并生成响应结果. jsp页面中添加servlet中加入下面代码: <jap:forward page="hello.jsp"/> RequestDispatcher rd=reques

51单片机之间的串口通信问题

问题描述 51单片机之间的串口通信问题 请问各位大虾,我要让两块51之间用串口进行通信,请问要怎么弄呢? 比如说我一块采集温度,将采集到的温度发送到另一块并在另一块显示出来,要怎么弄呢? 希望能详细点...谢谢... 解决方案 arm与51单片机之间串口通信实验arm与51单片机之间串口通信实验51单片机串口通信 解决方案二: 代码难得写,你找一下单片机多机通讯的书看看,硬件电路上两根串口线是交叉连接的.就是一个单片机tx连接另一个的rx 解决方案三: 网上也有详细的代码,方向给你说了,加油哦.

ZigBee CC2530两个之间怎么相互通信,相互传送数据?求大神帮忙

问题描述 ZigBee CC2530两个之间怎么相互通信,相互传送数据?求大神帮忙 ZigBee CC2530两个之间怎么相互通信?就是实现两个ZigBee板子之间相互传输数据 解决方案 ZigBee是一种近距离无线技术,类似蓝牙,wifi,NFC等等.Zigbee是IEEE 802.15.4协议的代名词,是一种短距离.低功耗的无线通信技术. 而CC2530是TI公司出的一款支持ZigBee技术的芯片. 然后组网:ZigBee组网

c++-java 和C++之间用socket通信

问题描述 java 和C++之间用socket通信 我现在做的是java socket服务端,然后和c++那边通信,我不知道怎么接受c++发的数据,然后判断,经过判断再返回相应的数据,该怎么做?谢谢 解决方案 1.big-endian与little-endian Endian定义:在计算机系统体系结构中用来描述在多字节数中各个字节的存储顺序. big-endian也称高位在前.大端在前.是计算机体系结构中一种描述多字节存储顺序的术语,在这种机制中最重要字节(MSB)存放在最低端的地址 上.采用这

android和js之间的bridge通信原理是什么

问题描述 android和js之间的bridge通信原理是什么 android webview和js之间的bridge通信原理是什么,最近只是简单的用到github上的一个库,请大神帮忙解答下. 解决方案 不是webview 吗 解决方案二: 没怎么研究过这个问题,

Android组件之间交互核心Intent用法分析_Android

本文实例讲述了Android组件之间交互核心Intent用法.分享给大家供大家参考,具体如下: 从一个Activity启动到另一个Activity可以使用startActivity()方法或者是startActivityForResult()方法 第一种:直接启动一个Activity Intent intent = new Intent(Main.this, SecondActivity.class); startActivity(intent); 第二种:启动另一个Activity并返回结果

Android实现Activity、Service与Broadcaster三大组件之间互相调用的方法详解_Android

本文实例讲述了Android实现Activity.Service与Broadcaster三大组件之间互相调用的方法.分享给大家供大家参考,具体如下: 我们研究两个问题, 1.Service如何通过Broadcaster更改activity的一个TextView. (研究这个问题,考虑到Service从服务器端获得消息之后,将msg返回给activity) 2.Activity如何通过Binder调用Service的一个方法. (研究这个问题,考虑到与服务器端交互的动作,打包至Service,Ac