redux 单向数据流的由来
- Flux将应用分成四个部分;
- view 视图层;
- Action 视图层发出的消息;(改变store里面的数据)
- Dispatch(派发器)
- Store (数据层) : 用来存在应用的状态(数据),一旦发生变动,就要提醒view更新页面。
redux单向数据流:
具体详情请见 阮一峰Flux架构入门Action
-
定义. Action 是把数据从应用(译者注:这里之所以不叫 view 是因为这些数据有可能是服务器响应,用户输入或其它非 view 的数据 )传到 store 的有效载荷。它是 store 数据的唯一来源。一般来说你会通过 store.dispatch() 将 action 传到 store。
-
狭义的Action
let action = {
type: 'ACTION_NAME',
...
}
复制代码
注意: 一般 type 的内容使用 大写字母+下划线 的格式.
-
广义的Action
广义的 action 是指在中间件的支持下,dispatch 函数可以调用的数据类型,除了普通action之外,常见的有 thunk, promise 等。我们用常用的 thunk来举个例子
什么叫thunk函数? 具体背景见阮一峰es6标准入门一书第17章Thunk函数的含义.在javaScript中函数将多参数函数替换成单参数的版本,且只接受回调函数作为参数。 例如:
var Thunk = function(fn){
return function(){
var args = Array.prototype.slice.call(arguments);
return function(callback){
args.push(callback);
return fn.apply.(this,args);
}
}
}
var readFileThunk = Thunk(fs.readFile);
readFileThunk(fileA)(callback);
复制代码
Thunk函数版本的action:
复制代码
(dispatch, getState) => {
//在函数体内可以使用 dispatch 方法来发射其他 action
//在函数体内可以使用 getState 方法来获取当前的state
}
复制代码
ceateStore
通过该API创建一个store对象,该对象包含四个方法;
- getState();获取store中当前的状态。
- dispatch(action): 分发一个action,并返回这个action,这是唯一能改变store中数据的方式。
- subscribe(listener): 注册一个监听者,它在store发生变化时被调用。
- replaceReducer(nextReducer): 更新当前store里的reducer, 一般只会在开发模式中调用该方法。
redux middleware
-
Redux 是一个简单的同步数据流,当分发一个action时,reducer收到action后,更新state并通知view重新渲染。 当action发出后如果想要执行一些别的操作,该怎样处理,也就是说action发出后没有立即执行reducer,将redux变成异步. 这时就要借助中间件。
-
redux-middleware的数据流动.
- 中间件的由来以及原理. 中间件的思想来源于koa. 核心思想:将middleware(函数)进行组合,将当前的middleware执行一遍作为参数传给下一个middleware去执行。
原理:
app.use((ctx, next) => {
ctx.name = 'Lucy'
next()
})
app.use((ctx, next) => {
ctx.age = 12
next()
})
app.use((ctx, next) => {
console.log(`${ctx.name} is ${ctx.age} years old.`) // => Lucy is 12 years old.
next()
})
// ... 任意调用 use 插入中间件
app.go({}) // => 启动执行,最后会调用 callback 打印 => { name: 'Lucy', age: 12 }
复制代码
ctx 参数就是 app.go 接受的对象。调用 app.go 其实会调用目标函数 app.callback,但是调用 app.callback 之前我们可以先让参数 ctx 通过一系列的中间件,最后才会传递给 app.callback。
使用 app.use 插入任意中间件,中间件是一个函数,可以被传入一个 ctx 和 next;调用 next 的时候会执行下一个中间件。如果不调用 next 会阻止接下来所有的中间件的执行,也不会执行 app.callback。
这里的app.use()就是一个实现中间件。
const app = {
middleware:[],
callback(){
console.log(ctx);
},
use(fn){
this.middleware.push(fn);
},
go(){
const reducer = (next,fn,i)=> {
fn(ctx,next)
}
this.middleware.reduceRight(reducer,this.callback.bind(this,ctx))();
}
}
复制代码
- redux的applyMiddleware的源码.
function applyMiddle(){
(next) => (reducer, initialState) => {
let store = next(reducer,initialState);
let dispatch = store.dispatch;
let chain = [];
let middlewarAPI = {
getState:Store.getState,
dispatch: (action) => { dispatch(action)}
}
chain = middlewares.map(middleware => middleware(middlewarAPI));
dispatch = compose(...chain)(store.dispatch);
return {
...store,
dispatch
}
}
}
复制代码
一般这样应用middleware
const finalCreateStore = compose(
applyMiddleware(...middleware)
//DevTools.instrument()
)(createStore);
const store = finalCreateStore(reducer);
复制代码
middleware的一般写法
const m1 = store => next => action => {
let result = next(action);
switch (action.type) {
case APP_INCREMENT_LOADING:
globalProgressBar.incrementLoading();
break;
case APP_DECREMENT_LOADING:
globalProgressBar.decrementLoading();
break;
}
return result;
};
export default m1;
复制代码
注:这里的compose函数请参考app.go或者参考上章FP一节; applyMiddle其实用了2个中间件的思想; 源码的详细解释: