由iOS原生开发转到React Native开发,再接着慢慢开始学习前端开发,真心觉得搞技术太难了这句话太正确了。当前正在开发的项目中使用了Vue+Vuex+Electron来实现桌面应用开发,在学习了Vuex之后,决定对之前学的各种数据流管理架构做一个系统的总结,所以接下来我还会总结
数据流架构学习笔记(二)-Redux
数据流架构学习笔记(三)-Vuex
数据流架构学习笔记(一)-Flux 是这次系统总结的第一篇笔记,都是一些自己的学习和总结,权当学习参考。
Flux是什么?
Flux是Facebook官方提出一种架构思想,他的出现同样也是为了解决实际项目中软件结构的问题,如果你了解过MVC,MVVM之类的东西,其实就应该知道这是一样的东西,他们是一种思想,为了让你的应用能够更加合理的工作和运行,具体到如何应用在你的项目中,通过代码和一些工具可以仁者见仁、智者见智的使用。
Flux如何工作
一个 Flux 应用主要包含四个部分:
-
the dispatcher
: 处理动作分发,并且向注册的回调函数广播payloads,维护 Store 之间的依赖关系 -
the stores
: 应用程序状态的容器,并且含有注册到Dispatcher的回调函数,数据和逻辑部分 -
the views
: 视图组件,这一层可以看作controller-views,作为视图同时响应用户交互 -
the actions
: 提供通过具体行为使用dispatcher 传递数据给 store,是一些使用Dispatcher传递数据的具体方法集合
Flux 的核心单向数据流
是这样运作的:
View -> Action -> Dispatcher -> Store -> View
更多时候 View 会通过用户交互触发 Action,所以一个简单完整的数据流类似这样:
假设现在在项目中,Action模块、Stroe模块、View模块等都已建立成功,Dispatcher来自官方Flux库,以从页面登录的例子进行一次Flux流程说明,流程如下:
- 页面点击登录按钮,View触发点击动作,调用Action中的网络请求封装函数;
- Action调用网络库相关API,并成功返回用户登录成功参数,或返回失败错误。
- 在成功返回的callback中通过Dispatcher分发用户信息Payload至Store更改数据并存储新数据中。
- store通过前期已注册的对应通知及emit()将最新的数据分发出去,页面监听到数据变化,从而更新页面数据,重新渲染页面。
实例应用
因为工作偏向React Native,这里以登录流程中部分React Native代码展示如何将Flux应用到React Native开发中进行数据管理,(由于代码时间较久,存在一些不合理之处请忽略,但不影响Flux数据流的理解):
视图层View:
登录页:
...
_login(userName, passWord) {
LoginActions.login({
username: userName,
password: passWord,
...
}, (response) => {
this.props.navigator.resetTo({comp:MainContainer});
}, (error) => {
Alert.alert(
'提示',
'error',
[{ text: '确定' }]
);
});
}
...
主页:
class Main extends Component{
constructor(props){
super(props);
this.state = {
user: AppStore.getUser(),
...
};
}
componentDidMount() {
AppStore.addChangeListener(this._userStateChange, 'USER_CHANGE');
}
componentWillUnmount() {
AppStore.removeChangeListener(this._userStateChange, 'USER_CHANGE');
}
_onChange: function () {
this.setState({
user: AppStore.getUser()
});
},
...
...
}
登录页是你的点击交互事件,你通过点击触发登录调用Action,主页Main会存在登录后返回的用户信息,数据来源于你的数据仓库AppStore,页面当然还存在页面监听者,知道当你的数据改变的时候,知道该如何去更新你的页面。
行为Action:
...
const _login = (params, callback, failure) => {
const requestUrl = CommonLink.login(params.username, params.password);
return Fetcher.getFetch(requestUrl)
.then((response) => {
AppDispatcher.dispatch({
actionType: AppConstants.LOGIN,
data: response.body,
});
callback(response);
}).catch((error) => {
failure(error);
});
};
...
module.exports = {
login: (params, callback, failure) => _login(params, callback, failure),
...
}
触发一个行为调用Action方法进行了网络API的调用,进行登录,并返回成功用户信息后,通过Dispatcher将数据和消息分发出去,把接下来的工作交给数据仓库Store。
数据仓库Stores:
const dataStore = {
user: {},
...
}
const AppStore = _.assign({}, EventEmitter.prototype, EventEmitter.prototype._maxListeners = 30, {
emitChange(event = 'DEFAULT_EVENT') {
this.emit(event);
},
addChangeListener(callback, event = 'DEFAULT_EVENT') {
this.on(event, callback);
},
removeChangeListener(callback, event = 'DEFAULT_EVENT') {
this.removeListener(event, callback);
},
...
getUser: () => dataStore.user || {},
...
});
...
// Register callback to handle all updates
AppDispatcher.register((action) => {
switch (action.actionType) {
...
case AppConstants.LOGIN:
_.assign(dataStore, {
username: action.data.user.username,
...
});
AppStore.emitChange('USER_CHANGE');
break;
...
}
});
module.exports = AppStore;
在数据仓库中,你应该定义出仓库对象AppStore,并对AppDispatcher注册入各种操作,即当接收到AppDispatcher发来的不同消息时,操作数据并保存数据到dataStore中,之后通过AppStore.emit()将更新通知发送到页面中,让页面进行重新渲染。从而完成整个Flux数据流的闭环。
关于AppDispatcher和AppConstants
上述代码中用到的AppDispatcher和AppConstants代码如下:
AppDispatcher:
import {Dispatcher} from 'flux'
module.exports = new Dispatcher();
AppConstants:
const keyMirror = require('keymirror');
const AppConstants = keyMirror({
...
LOGIN: null,
...
});
module.exports = AppConstants;
可以看出这些只是为了更好的使用Flux而引入库和辅助工具,你也可以使用其他类似工具。
总结
Flux学习和理解需要的是在项目中实际应用进去,同样只要理解了单向数据流的思想,理解Flux也是很快的,Flux是单向数据流的一种具体架构实现。接下来会再总结关于Redux的理解和使用,同样也是单向数据流的一种具体实现,基于Flux,但是比Flux更加方便和强大。而当前的很多React开发项目也都基于使用Redux。
虽然搞技术很难,但是做自己喜欢的事情还是很开心的,一起学习,努力奋斗。
参考博客:
Flux 架构入门教程-阮一峰
详解React Flux架构工作方式