上回说到,Reflux将React之间多个组件之间的通信问题解决了,保证了这个应用的数据统一,总结一下就是:
Component是一个界面渲染角色,会有自己的状态,可以传递属性
Actions是用户操作的接口,它并没有Controller那样强大的控制能力,我的理解是定义了一个操作的内部RESTFUL操作规范,每一个涉及到数据的操作,都必须通过actions,这样对于以后复杂的流程和数据模型,我们内部不用把界面写得乱七八糟。
Store是存储数据的地方,也就是MVC中的Modal,但是很多逻辑我们又不得不放在Store里面,所以Store更像Controller。Store的数据一旦变化,它会通知各个监听他的组件对象,重新对界面进行渲染。
这一章,我们还是拿UserActions和UserStore来举例说明,在我们的项目中,如何更好的使用Reflux。
目前我们的UserActions是这样的:
var UserActions = Reflux.createActions({
'register' : {children:["success","Failed"]},'login' : {children:["success",'loginWithToken' : {children : ['success','Failed']},'logout' : {children:["success"]},'openLogin' : {children:["success",'currentUser' : {children:["success",'modifyPassword':{children:["success","Failed"]}
});
看action的命名应该就知道大概的用途了,这里不细说。我们的UserStore是这样初始化的:
init: function() {
console.log('UserStore initialized'); /* 需要增加从localStorage读取用户信息的方法来初始化userData */ this.userData = { userId: '',userName: '',loginToken : '',//用户选择rememberme的时候返回 userType: '',userState: '',isLogin: false,hintMessage: '',flag : '' }; /* 获取第三方登录的返回值,并得到当前用户 */ UserActions.currentUser(); /* 可以用下面代码代替 listenables: UserActions, */ this.listenTo(UserActions.login.success,this.onLoginSuccess); this.listenTo(UserActions.login.Failed,this.onLoginFailed); this.listenTo(UserActions.register.success,this.onRegisterSuccess); this.listenTo(UserActions.register.Failed,this.onRegisterFailed); ....
},
我们定义了一个userData对象,会存储当前的用户信息,如果没有登录状态,isLogin是false。请注意,我们在UserStore里面会初始化调用一个UserActions.currentUser().也就是说在页面一加载的时候,我们就会调用获取当前用户的登录信息。
得到用户信息的反馈之后:
onGetCurrentUser : function(data){
if(data.Success){ console.log(data); this.setCurrentUser(data); this.userData.flag = 'currentUser'; this.trigger(this.userData); }else{ console.log(data.ErrorMsg); //若未得到当前用户,尝试loginwithtoken this.getTokenToLogin(); }
},
很容易明白上面的代码,如果后端返回成功,设置当前用户,如果后端失败,尝试用本地的loginToken登录。但是注意到了没有,为什么会有一个flag呢?当然你可能根本没有注意到。。。。
flag是我自己定义的一个标记,并不是Reflux的定义,为什么要定义?回头看看UserActions的代码,发现那么多的actions都是调用同一个UserStore,用户登录、注册、三方登录、修改密码等等。监听UserStore的组件相当多,一般涉及到需要当前用户登录才能操作的界面基本上都要监听UserStore,如果不管进行什么操作,这些组件都要听到UserStore数据变化的消息,那不就烦(luan)死(tao)啦。所以,我们针对每一个不同的actions操作返回的结果定义一个flag,在不同的组件监听方法里面判断这次数据的变化是不是我想要听到的,如果不是就不管他。
于是component里面的代码就是这样的:
//login.js
handleLoginResult : function(data){
if(data.flag == 'login' || data.flag == 'currentUser' || data.flag == 'loginToken'){ if(data.hintMessage){ this.handleHint(data.hintMessage); }else{ //登录成功,跳转到account界面 console.log('登录成功'); this.history.pushState(null,'/account'); } }
},
当然,对于UserStore里面的信息是非常重要的,所以对于它而言,一般需要登录才能操作的界面,我们直接不判断他是从哪登录的,只要登录就行,就不用判断flag。比如摄影师的编辑页面是这样的监听方法:
handleUserStoreChange : function(userData){
if(userData.isLogin){ if(userData.userType == 1){ //已经是摄影师用户,跳转摄影师信息 this.history.pushState(null,'/account/photographer'); }else{ //普通用户,拿到认证数据再判断认证状态 this.getAuditData(); } }else{ //没有登录转到登录界面 this.history.pushSate(null,'/'); }
},
对于程序员而言,代码是最能说明事情的方法,所以大量的引用了代码,对于你们的困扰,我说声抱歉。当然,如果你能仔细看懂上面的例子,目前对于我们的项目而言,处理各种类型的逻辑应该是不成话下了。
未完待续,下一篇讲讲Router,其实我更想讲讲react-native,算了,这两天搞的头大,直接上swift了。