前言
redux并不局限于flux与react。redux 自身保持简洁以便适配各种场景,让社区发展出各种 redux-* 中间件或者插件,从而形成它自己的生态系统。
主要关系
reducer 声明了state的初始值,以及当前state接受action对象之后处理为new state的逻辑。
createStore接受reducer作为参数,返回产生的store,store其实是一个含有state的闭包,以及提供将action分发给reducer的dispatch方法。
applyMiddlewares方法接受n个middlewares作为参数返回一个用于渲染creatorStore函数的方法。
applyMiddleware可以向actionCreator提供store.dispatch以及getState方法,用以增强actionCreator的能力
store主要包含以下三个核心方法:
dispatch 将action按顺序经过各middle处理后派发给reducer
action 流程图
createStore
createStore是根据reducer中的规则创建store的方法。
特性
源码
//此处为示意,不是 redux 的源码本身 export default createStore(reducer,initialState) { //闭包私有变量 let currentState = initialState let currentReducer = reducer let listeners = [] //返回一个包含可访问闭包变量的公有方法 return { getState() { return currentState //返回当前 state },subscribe(listener) { let index = listeners.length listeners.push(listener) //缓存 listener return () => listeners.splice(i,1) //返回删除该 listener 的函数 },dispatch(action) { //更新 currentState currentState = currentReducer(currentState,action) // 可以看到这里并没有用到eventEmitter等 listeners.slice().forEach(listener => listener()) return action //返回 action 对象 } } }
action
action有以下特点:
pure object
描述reducer响应的事件类型
携带所需要的数据
actionCreator
用于描述action的dispatch的逻辑。
action的重用
数据的预处理
action的特殊处理逻辑
reducer
reducer应该是是一个无副作用函数,以当前的state以及action为参数,返回新的state。
每次返回一个新State的好处是在shouldComponentUpdate过程中可以使用高性能的shallow equal。
pure function
接受initialState
don't modify the state!!!
//reducer 接受两个参数,全局数据对象 state 以及 action 函数返回的 action 对象 //返回新的全局数据对象 new state export default (state,action) => { switch (action.type) { case A: return handleA(state) case B: return handleB(state) case C: return handleC(state) default: return state //如果没有匹配上就直接返回原 state } }
combineReducers
将一个reducer map转换为一个reducer。方便对复杂的reducer进行功能拆分。
problem
state 结构太复杂
希望根据对应的component进行维护
how to use
var reducers = { todos: (state,action) { //预期此处的 state 参数是全局 state.todos 属性 switch (action.type) {...} //返回的 new state 更新到全局 state.todos 属性中 },activeFilter: (state,action) { //预期拿到 state.activeFilter 作为此处的 state switch (action.type) {...} //new state 更新到全局 state.activeFilter 属性中 } } //返回一个 rootReducer 函数 //在内部将 reducers.todos 函数的返回值,挂到 state.todos 中 //在内部将 reducers.activeFilter 函数的返回值,挂到 state.activeFilter 中 var rootReducer = combineReducers(reducers)
源码
//combination 函数是 combineReducers(reducers) 的返回值,它是真正的 rootReducer //finalReducers 是 combineReducers(reducers) 的 reducers 对象去掉非函数属性的产物 //mapValue 把 finalReducers 对象里的函数,映射到相同 key 值的新对象中 function combination(state = defaultState,action) { var finalState = mapValues(finalReducers,(reducer,key) => { var newState = reducer(state[key],action); //这里调用子 reducer if (typeof newState === 'undefined') { throw new Error(getErrorMessage(key,action)); } return newState; //返回新的子 state }); //...省略一些业务无关的代码 return finalState; //返回新 state }; function mapValues(obj,fn) { return Object.keys(obj).reduce((result,key) => { result[key] = fn(obj[key],key); return result; },{}); }
applyMiddleWares
problem
异步action
promise
个性化 action 响应
log
描述
接受 middleWares 将 store 修饰为使用了 middlwares 的 store,其实是用被高阶函数修饰过的dispatch替换掉了原来的dispatch。
usage
var craeteStoreWithMiddleWare = applyMiddleWare(thunk)(createStore); //redux-thunk export default function thunkMiddleware({ dispatch,getState }) { return next => action => typeof action === 'function' ? // action 居然是函数而不是 plain object? action(dispatch,getState) : //在中间件里消化掉,让该函数控制 dispatch 时机 next(action); //否则调用 next 让其他中间件处理其他类型的 action }
源码
这里的composeMiddleware可能不是很好理解,这里有一个简单的例子方便大家理解。http://jsbin.com/xalunadofa/1/edit?js,console。 compose可以理解为倒叙一层层打包的过程,因此最后调用composedFunction的时候会顺序进入各个middlewares。
function applyMiddleware(...middlewares) { return next => (...args) => { const store = next(...args); const middleware = composeMiddleware(...middlewares); // dispatch 被middlWare修饰 function dispatch(action) { const methods = { dispatch,getState: store.getState }; return compose( middleware(methods),store.dispatch )(action); } // 返回新的store dispatch被新的dispatch替代 return { ...store,dispatch }; }; }
bindActionCreator
源码
//将 actionCreator 跟 dispatch 绑定在一起 let bindActionCreator => (actionCreator,dispatch) { return (...args) => dispatch(actionCreator(...args)); } function bindActionCreators(actionCreators,dispatch) { if (typeof actionCreators === 'function') { //如果是单个 actionCreator,绑定一词 return bindActionCreator(actionCreators,dispatch); } //返回一个改造过的「函数组合」 return mapValues(actionCreators,actionCreator => bindActionCreator(actionCreator,dispatch) ) }
connector
connector 接受mapStatetoProps,mapdispatchToProps,Component 三个参数,返回一个能够自动关联store中state以及dispatch事件的smart component
由于connector代码过长,只对重要的几个函数进行说明。
connetor函数接受的两个参数指明从store的state中挑选哪些作为props,以及将哪些actionCreator绑定到porps中。
订阅store的change事件,当store更新时计算新的state,与旧state进行浅对比,如果不同则更新state,并render,否则不进行render。
// 根据从store中select的state以及dispatch绑定的actionCreator计算新的props computeNextState(props = this.props) { return computeNextState( this.stateProps,this.dispatchProps,props ); } // 与旧值进行shallow equal updateState(props = this.props) { const nextState = this.computeNextState(props); if (!shallowEqual(nextState,this.state.props)) { this.setState({ props: nextState }); } } // 订阅change事件 trySubscribe() { if (shouldSubscribe && !this.unsubscribe) { this.unsubscribe = this.store.subscribe(::this.handleChange); this.handleChange(); } } tryUnsubscribe() { if (this.unsubscribe) { this.unsubscribe(); this.unsubscribe = null; } } componentDidMount() { this.trySubscribe(); } componentwillUnmount() { this.tryUnsubscribe(); } handleChange() { if (!this.unsubscribe) { return; } if (this.updateStateProps()) { this.updateState(); } }
结语
欢迎大家发起pr完善文档,进行讨论。