写这篇文章,不是把官方的例子或者github的例子给大家敲一遍,而是想把自己学习遇到的问题重点突出,让大家少走弯路。
首先,学习这篇文章的时候,需要有React基础,本文分为两部分主要讲解Reflux,第一部分给出其基本原理,第二部分给出一个我认为比较易懂的例子来说明组件间通信的具体实现方式。
1.reflux 基本工作原理
reflux是目前github上flux类型架构,比较流行的一种实现类库,它可以使React组件互相通信。React在不用Reflux的时候也能够通信,但是会比较繁杂,导致数据经过很多间接组件,会导致维护修改成本增高。在reflux的帮助下,组件间可以轻松实现通信,不论组件间是上下级关系还是并列关系。reflux工作原理比较简单,如果你和我一样主要开发后台程序或对后端开发也比较熟悉,那么reflux理解起来会特别容易。简单说,reflux主要工作模式就是pubsub,那么它是怎么实现消息发布和订阅的,在reflux有几个关键的角色,分别是:Actions,Stores,viewComponets,action在这里就相当于请求,就是发布消息,那么消息发布到哪里呢?你猜对了,发送到Stores,Store就像一个中间人,一般在这里,可以暂存数据,而且可以访问后台程序,将数据传入后台,后台处理完再返回数据,所以这一层比较重要。Store接收到数据的下一步步奏,就是唤醒所有订阅者,并给订阅者发送数据。最后当然是viewComponets,这就是react中的组件,这些组件想要收到消息那么需要订阅store,收到消息再进行别的处理。
下面用一段比较简单的代码来介绍整个流程。
2.实用示例
前提,编写这段代码的时候用brackets写的,没有用服务器,直接在几个文件中写的,所以运行代码的时候没有必要实用服务器。类库下载,react.js可以到处下载,而reflux的下载,需要在github下载。
例子布局很简单,一个main.html 中有3三个div,从上到下的顺序分别是:<div id="header"></div> ,<div id="main"></div> ,<div id=“footer”></div>,具体代码如下:
代码语言:javascript复制 <div id="header" class="container">
</div>
<div id='main' class="container">
</div>
<div id="footer" class="container">
</div>
这三个div分别对应,页面中header,body,footer,组件设计很简单,header中放置组件Header,main中放置组件Body,footer中放置组件Footer,具体布局如下:
代码语言:javascript复制 ReactDOM.render(
<Header headerName="reflux Test"/>
,
document.getElementById("header")
);
ReactDOM.render(
<Body/>
,
document.getElementById("main")
);
ReactDOM.render(
<Footer/>
,
document.getElementById("footer")
)
通信流程很简单,Header组件,每点击一次按钮,就把输入框的消息,发送给Body组件,和Footer组件,而Body和Footer收到消息则展示,如下图:
如图所示从上到下,没一个灰色框就代表一个组件,在输入框中输入内容,点击输入显示内容,就将消息发送出去了,下面body,footer收到就显示出来。下面先具体看看reflux的Action,stores是怎么实现的,将reflux代码放到js文件中,具体实现如下:
代码语言:javascript复制/*通信组件*/
//请求定义(action)
var HeaderActions = Reflux.createActions([
'clickShowInBody'
]);
//请求接收,以及响应定义(store)
var HeaderStore = Reflux.createStore({
/*可以添加成员变量*/
listenables:[HeaderActions] /*可以同时监听多个请求,所以是数组*/
,
onClickShowInBody:function(model){//注意model为调用aciton传过来的参数
//收到请求的回调函数
console.log(model);
var returnData;
//1.打印请求传过来的数据
//2.拿着数据做处理
returnData = model;
//3.发送return的数据给订阅该事件组件
this.trigger(returnData);
}
});
代码如上,是不是特别简单,对的,这时最简单的一种实现,但是麻雀虽小五脏俱全。
1.我们首先解释一下Actions的实现:首先需要调用Reflux的创建Action的方法,明显参数是一个数组,所以可以定义多个请求,明显我们的HeaderActions比较简单。发送消息的时候 调用形式如下 actionsName.XXXXX(data),例如HeaderActions.clickShowInBody("123"),的含义就是,发送action请求,并携带数据“123”。
2.下面我们解释一个Stores的实现,他负责请求的接收和响应:首先需要调用Reflux创建Store的方法,开始我们可以看到有一个listenables:[HeaderActions],明显意思就是监听,HeaderActions,而下面的onClickShowInBody 则是Actions中clickShowInBody的回调方法,reflux规定,回调方法同意命名为on actionName ,并且actionName第一个字母大写。如果store接收到消息,那么就会进入回调方法中,并且入参model为action携带的数据。下面就是触发监听该Store的组件,将数据发送到组件,那么调用trigger(data)函数就可以,这样就可以出发监听的所有组件接收数据。reflux怎么工作应该已经聊明白了,那么下面我们具体看一下,reflux和React是怎么协同工作的,下面看看,三个组件的具体实现。
代码很简单,有几个关键的地方: 1.首先是Header中发射请求的地方,就是handleClick方法中,headerActions.clickShowInBody(content),这行代码就是为了发送action的, 2.其次就是对于Store的监听,如Body和Footer组件中,有代码 Reflux.listenTo(HeaderStore,'handleEvent') ,其中第一个是参数是Store,第二是参数是,响应的回调函数,handleEvent用来处理收到数据之后的事情。当然回到函数的名字可以随便定义,但是还是定义为handle开头,比较容易懂。 除了这两点以外其他地方,都是熟悉的react代码。好了,这虽然只是一个简单的例子,但是我认为也比较有代表性,就先聊到这里,如果写的有不对的地方,欢迎大家指正,谢谢!!!
代码语言:javascript复制
代码语言:javascript复制var Header = React.createClass({
getInitialState:function(){
return {
headerName:"index"
}
}
,
handleClick:function(){
var content = eval(document.getElementById("edit")).value;
console.log(content);
HeaderActions.clickShowInBody(content);//发送action请求
}
,
render:function(){
var headerName = this.props.headerName;
return (
<div className='panel panel-default'>
<h1>{headerName}</h1>
<h3>
<input id="edit" type="text"></input>
<button className ='btn btn-info btn-sm' onClick={this.handleClick}>输入显示内容</button>
</h3>
</div>
)
}
});
var Body = React.createClass({
mixins: [Reflux.listenTo(HeaderStore, 'handleEvent')],//监听store,回调方法名字为handleEvent
handleEvent:function(data){
console.log(data);
this.setState({
content:data
})
}
,
getInitialState:function(){
return {
content:"body"
}
}
,
render:function(){
var content = this.state.content;
return (
<div className='panel panel-default'>
<p>{content}</p>
</div>
)
}
});
var Footer = React.createClass({
mixins:[Reflux.listenTo(HeaderStore, 'handleEvent')], //监听store,回调方法名字为handleEvent
getInitialState:function(){
return {
content:'footer'
}
}
,
handleEvent:function(data){
this.setState({
content:data
});
}
,
render:function(){
var content = this.state.content;
return (
<div className='panel panel-default'>
<p>{content}</p>
</div>
)
}
});