Flux,Redux,Vuex整理总结
关于前端架构中的状态管理方法论,经常能听到的Flux, Redux 和Vuex,这些方法论乍一看好像都差不多,再一看又有一些区别,这是我刚刚接触这些东西时的一个直观感受。看了很多其他人写的文章,自己又画了点图谢谢品味了一下,我决定还是把它们写出来,既能巩固所得,又可以方便以后时常温习。记得React刚出来不久时,Flux还是React官方指定,Redux那会儿还没有影,当时认真看了Flux,隔..
关于前端架构中的状态管理方法论,经常能听到的Flux, Redux 和Vuex,这些方法论乍一看好像都差不多,再一看又有一些区别,这是我刚刚接触这些东西时的一个直观感受。看了很多其他人写的文章,自己又画了点图谢谢品味了一下,我决定还是把它们写出来,既能巩固所得,又可以方便以后时常温习。
记得React刚出来不久时,Flux还是React官方指定,Redux那会儿还没有影,当时认真看了Flux,隔了一年多再回头竟然忘了个干净,有人问到我时的表现像是完全没听说过。这也是我重新看过之后决定整理一下的原因。
参考文章中有阮大神早些的力作,代码片段直接拿来主义了:
Flux 架构入门教程
Redux 入门教程
废话不多少,言归正传,关于Flux, Redux和Vuex三者的关系呢,先用一句话总结:
它们都是基于单向数据流的状态管理方法论。Flux最早提出,作为对传统前端MVC的一种改进(我不认为是颠覆)。Redux深受Flux的启发,又加入了函数式编程的思想,算是Flux的极大增强版本。Vuex可以说是基于Flux并且吸收了Redux的一些特点,但它与Vue是紧密捆绑的。Redux其实除了在React中广泛应用,Angular.js以及Angular2中也完成了它的实现。
Flux 要点
备注:虚线小红框会在比较Redux和Flux时用到。
- View:
- 确定相应的Store以及监听其变化来更新视图。
- 发起Action。
// Get binding store
var ListStore = require('../stores/ListStore');
.....
// Subscribe store change event
componentDidMount: function() {
ListStore.addChangeListener(this._onChange);
}
...
// Pass action to Dispatcher
createNewItem: function (event) {
// There's a dispatcher instance in ButtonActions
ButtonActions.addNewItem('new item');
}
Action:
- 每个Action都是一个对象,包含一个actionType属性(说明动作的类型)和一些其他属性(用来传递数据)
Dispatcher:
- 全局唯一。
- 逻辑简单,只用来派发action去相应的store。
- 通过 AppDispatcher.register() 来登记各种Action的回调函数。
// dispatcher/AppDispatcher.js 全局唯一
var Dispatcher = require('flux').Dispatcher;
var ListStore = require('../stores/ListStore');
module.exports = new Dispatcher();
.....
//注册action回调函数
AppDispatcher.register(function (action) {
switch(action.actionType) {
case 'ADD_NEW_ITEM':
ListStore.addNewItemHandler(action.text);
ListStore.emitChange();
break;
default:
// no op
}
})
// actions/ButtonActions.js。dispatch方法只用来分发action
var AppDispatcher = require('../dispatcher/AppDispatcher');
var ButtonActions = {
addNewItem: function (text) {
AppDispatcher.dispatch({
actionType: 'ADD_NEW_ITEM',
text: text
});
},
};
- Store:
- 存放view中的数据。
- 发送change事件,通过view中定义的handler捕捉变化。
var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
var ListStore = assign({}, EventEmitter.prototype, {
// data in View
items: [],
.......
emitChange: function () {
this.emit('change');
},
addChangeListener: function(callback) {
this.on('change', callback);
}
....
});
Redux 要点
What is Redux
- A single, immutable data store.
- One-way data flow.
- An approach to change based on pure functions and a stream of actions.
Redux 设计思想
(1)Web 应用是一个状态机,视图与状态是一一对应的。
(2)所有的状态,保存在一个对象里面。
Redux vs Flus: Redux = Reducer + Flux
1.Redux将Flux中的Dispatcher并入了Store。也可以理解为Redux没Dispatcher。Redux的设想是用户永远不会变动数据,应该在reducer中返回新的对象来作为应用的新状态。
2.Redux增加了Reducer.
注:通过代码对比的直观感受就是Flux中的view需要知道具体对应哪个store。而在Redux中,store成为一个被所有view共享的公共对象,view只需要通过store.dispatch()来发送action,无需关心具体处理函数。
- View:
- 通过全局唯一的store dispatch action 以及获取最新state
注: 通过对比flux的view 部分可以看出在Redux中,view不会关心具体的处理函数,只专注于收发就好。
- 通过全局唯一的store dispatch action 以及获取最新state
- Store:
- 全局唯一
- 包含整棵state树: state 和 view 是一一对应的关系
- Dispatcher功能已被整合进store:store.dispatch()
- state 一旦有变化,store 就会调用通过store.subscribe()注册的回调函数(一般是render)。
- Reducer的拆分就先不讲了。
const Counter = ({ value, onIncrement, onDecrement }) => (
<div>
<h1>{value}</h1>
<button onClick={onIncrement}>+</button>
<button onClick={onDecrement}>-</button>
</div>
);
const reducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT': return state + 1;
case 'DECREMENT': return state - 1;
default: return state;
}
};
const store = createStore(reducer);
const render = () => {
ReactDOM.render(
<Counter
value={store.getState()}
onIncrement={() => store.dispatch({type: 'INCREMENT'})}
onDecrement={() => store.dispatch({type: 'DECREMENT'})}
/>,
document.getElementById('root')
);
};
render();
store.subscribe(render);
- Action:
- 普通对象,作用与Flux中相同
const action = {
type: 'ADD_TODO', //必填字段
payload: 'Learn Redux'
};
- Reducer:
- reducer是current stae 和 action 为参数计算new state的纯函数。
- 纯函数无副作用:不能调用系统 I/O 的API,不能调用Date.now()或者Math.random()等不纯的方法,因为每次会得到不一样的结果 blabla…
const defaultState = 0;
const reducer = (state = defaultState, action) => {
switch (action.type) {
case 'ADD':
return state + action.payload;
default:
return state;
}
};
const state = reducer(1, {
type: 'ADD',
payload: 2
});
// Reducer 是纯函数,就可以保证同样的State,必定得到同样的 View。
// 但也正因为这一点,Reducer 函数里面不能改变 State,必须返回一个全新的对象,请参考下面的写法。
function reducer(state, action) {
return Object.assign({}, state, { thingToChange });
// Or
return { ...state, ...newState };
}
// State 是一个数组
function reducer(state, action) {
return [...state, newItem];
}
Vuex 要点
这是一张来自Vuex官网的图:
下面的图是我重新画的,风格与之前的Redux和Flux的数据流图相同,以便与比较:
注;代码片段来自Vuex 官方文档
Redux vs Vuex:
- 使用mutation来替换redux中的reducer
- Vuex有自动渲染的功能,所以无需要专门监听state。(this.$store.getters.doneTodosCount)
- Vuex中的action是一个函数集合对象,用于async/sync commit mutaions. 和Redux或者Flux中的action只是简单对象有本质不同,只是叫了一个相同名字。
注:个人认为action和mutation合在一起就是Redux中的Reducer
先到这里吧,想到什么新的东西再来补充。以上是我对前端状态管理方法论的个人理解,可能有错误的地方,欢迎指正:)
更多推荐
所有评论(0)