在React App中使用Flux

FluxFacebook推出的一种应用程序架构,用于构建客户端Web应用。Flux使用一种名为单向数据流的模式,比传统的MVC模式简明。

我在《使用Gulp转换React的JSX》示例基础上,增加了提交新评论的功能,并使用了Flux,用来说明Flux的基本使用。

示例代码:https://github.com/MarshalW/ReactDemos/tree/comment-m5

运行示例:

下面说下实现的步骤。

对所需库文件的处理

使用BrowserifyGulp可以很方便的加载Flux+React所需的库:

  • flux
  • react
  • object-assign,配合event使用

将这些加入到`package.json’文件中,并通过下面命令安装:

1
npm install

在js文件中引用所需的库,见js/comments.js

1
2
3
4
var React = require('react');
var Dispatcher = require('flux').Dispatcher;
var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');

然后,通过gulp命令生成单一的js文件:bundle.js

html代码(见comments.html)中只引用bundle.js即可:

1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="content"></div>
<script src="js/bundle.js"></script>
</body>
</html>

使用Flux

如上介绍的,本示例依赖这些库:

  • flux,提供了Dispatcher支持,Dispatcher,提供事件广播和收听功能,代码可以注册收听事件广播,也可向它发送事件
  • react,用于view的生成
  • EventEmitter,是nodejs自带的事件支持库,借助browserify,我们可以在浏览器端使用它,assign库用于配合EventEmitter,方便集成EventEmitter到任意对象上

Dispatcher,点击提交按钮时,用于广播事件

代码见js/comments.js

创建Dispatcher

1
var AppDispatcher=new Dispatcher();

这个对象是全局唯一的。

当表单提交时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var CommentForm = React.createClass({
handleSubmit: function(e) {
e.preventDefault();
var title = this.refs.title.getDOMNode().value.trim();
var content = this.refs.content.getDOMNode().value.trim();
if (!title || !content) {
return;
}
this.refs.title.getDOMNode().value = '';
this.refs.content.getDOMNode().value = '';

AppDispatcher.dispatch({
eventName: 'new-item',
newItem:{title: title, content: content}
});
return;
},

使用’AppDispatcher.dispatch(..)’方法广播一个事件:添加新的评论条目(new-item)。

Store,用于存储评论的集合

Flux第二个概念是’Store’,用于处理实际的业务逻辑和数据,比如存储/返回评论对象的集合:

1
2
3
4
5
6
7
8
9
10
11
12
var CommentStore=assign({}, EventEmitter.prototype, {
items:[
{
title:'不错,超级满意',
content:'样子漂亮,买之前还在担心有什么问题,是我多想了,很实用,很好'
},
{
title:'还不错',
content:'送人的礼物,很满意的购物'
}
]
});

这里通过assign,让CommentStore对象混入(mixinEventEmitter的函数。

在这里注册一个回调,用来收听到所有Dispatcher的广播:

1
2
3
4
5
6
7
8
9
AppDispatcher.register(function(payload){
switch( payload.eventName ) {
case 'new-item':
CommentStore.items.push( payload.newItem );
CommentStore.emit('change');
break;
}
return true;
});

并根据eventName过滤出自己所需的事件,做了如下事情:

  • 根据事件中数据,为评论集合添加新的条目
  • 触发评论数据修改的事件(使用nodejs的EventEmitter

view对数据变化的响应

在React view(视图)的代码中:

1
2
3
4
5
6
7
8
var CommentBox=React.createClass({
getInitialState: function() {
var self=this;
CommentStore.on('change',function(){
self.setState(CommentStore.items);
});
return {data:CommentStore.items};
},

监听change事件,如果发生,就通过setState方法重新设置数据。React发现State变化了,会重新绘制(render)该视图。

本文参考了以下内容

如下: