redux源码分析

主要分为以下几块

  • createStore
  • combineReducers
  • bindActionCreators
  • applyMiddleware
  • compose
  • utils
createStore

createStore 接受3个参数reducer、preloadedState(初始状态)、enhancer(store增强器,只能用applyMiddleWare方法来生成)

默认执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ...
// createStore构建reducer的
enhancer(createStore)(reducer, preloadedState)
// ...
dispatch({
type: '@@redux/INIT'
})
// ...
return {
dispatch, /* 派发action,执行reducer,执行subscribe的所有listener */
subscribe, /* 订阅事件,返回unsubscribe函数,取消当前的订阅 */
getState, /* 获取当前状态 */
replaceReducer, /* 替换reducer,dispatch init */
}
applyMiddleWare

返回一个函数,封装middleware中间件。
这个函数接受createStore参数,返回一个新store,主要是改写dispatch方法
源码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
var store = createStore(reducer, preloadedState, enhancer)
var dispatch = store.dispatch
var chain = []
// 暴露两个方法给外部,例如redux-thunk就是接受这两个参数
var middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}

redux-thunk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function createThunkMiddleware(extraArgument) {
return function(dispatch, getState){
return function(next){
return function(action){
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
}
}
}
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
combineReducers

combineReducers接受一个参数:reducers,数组类型
返回一个新的reducer

新的reducer执行时会依次取之前定义的每个reducer并将返回值付给分别的相应的state

bindActionCreators

将action creater转为dispatch action(react-redux中的connect就使用了该函数)
bindActionCreators接受两个参数:actionCreators,dispatch

compose(…functions)

源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function compose() {
for (var _len = arguments.length, funcs = Array(_len), _key = 0; _key < _len; _key++) {
funcs[_key] = arguments[_key];
}
if (funcs.length === 0) {
return function (arg) {
return arg;
};
}
if (funcs.length === 1) {
return funcs[0];
}
var last = funcs[funcs.length - 1];
var rest = funcs.slice(0, -1);
return function () {
// composed表示上一次执行的结果,f表示当前值
return rest.reduceRight(function (composed, f) {
return f(composed);
}, last.apply(undefined, arguments));
};
}

从右到左组合多个函数,还有一个与之相对的方法pipe,在Lodash中叫做flow,他们的区别在于flow是从左到右执行

1
2
3
4
// compose简化写法
const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);
// pipe简化写法
const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x);

关于compose的一个实用技巧,可以用来trace函数运行的过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const trace = curry((label, x) => {
console.log(`== ${ label }: ${ x }`);
return x;
});
const toSlug = pipe(
trace('input'),
split(' '),
map(toLowerCase),
trace('after map'),
join('-'),
encodeURIComponent
);
console.log(toSlug('JS Cheerleader'));
// '== input: JS Cheerleader'
// '== after map: js,cheerleader'
// 'js-cheerleader'

函数式编程中的方法,当需要吧多个store增强器依次执行时,会用到它

如下

1
2
3
4
5
6
7
8
9
// compose 对一个参数,依次从右向左执行函数,并且讲上一个函数的输出作为下一个函数的输入,有点类似于shell里面的管道
var compose = (fn1, fn2) => (arg) => fn1(fn2(arg));
var fn1 = arr => arr.concat(5);
var fn2 = arr => arr.concat(6);
var a=[1,2,3]
var b = compose(fn1,fn2);
var c=b(a);
console.log(c); //[1,2,3,6,5]

一般使用如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import makeRootReducer from './reducers';
import thunk from 'redux-thunk'
const middleware = [thunk/*,loggerMiddleware*/]
const enhancers = []
// ...
const store = createStore(
makeRootReducer(), // reducer
initialState, // 初始状态
compose( //enhancer
applyMiddleware(...middleware),
...enhancers
)
)
// ... createStore中
enhancer(createStore)(reducer, preloadedState)

资源检索