前言
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主要包含以下三個核心方法:
- subscribe 注冊store更新之后的回調函數
- getState 獲取store當前state的引用,切記直接修改返回的結果
- dispatch 將action按順序經過各middle處理后派發給reducer
action 流程圖

createStore
createStore是根據reducer中的規則創建store的方法。
特性
- 提供dispatch
- subscribe
- getState // getState拿到的是state的引用!不要直接修改
- 提供初始值initialState
源碼
//此處為示意,不是 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完善文檔,進行討論。