React實戰-深入原始碼瞭解Redux用法之Reducers
React實戰-深入原始碼瞭解Redux用法之Reducers
在Redux中Reducers是真正實現state資料變化的工作。我們在使用Redux時,可能也只是似懂非懂,我們不知道它是如何工作的,我們知道在Action中定義事件,在Reducers中定義對應事件對應的操作,我們知道他們有關係,但如何建立的關係不知道(微信:react-javascript)。
1.Flux中事件的定義
還是看看Flux中是如何定義的吧,在Flux中,事件流是非常清楚的。
a.我們定義Action
module.exports = {
deletePersonByID: function(id) {
AccountDispatcher.dispatch({
type: ActionTypes.DELETE_PERSON,
id: id
});
}
}
b.在store中定義事件和action對於的操作
定義事件:var CHANGE_EVENT = 'change';
定義事件繫結與解繫結:
addChangedListener(callback)
{
this.on(CHANGE_EVENT, callback);
},
removeChangedListener(callback){
this.removeListener(CHANGE_EVENT, callback);
}
定義事件對應的操作:
PersonDispatcher.register(function (action) {
switch (action.type) {
case ActionTypes.DELETE_PERSON:
PersonStore.deleteByID(action.id);
break;
}
}
c.在comonent中關聯事件:
componentDidMount(){
PersonStore.addChangedListener(this._onChange);
},
componentWillUnmount(){
PersonStore.removeChangedListener(this._onChange);
},
整個過程清楚明瞭。
2.Redux中卻少了很多環節
a.定義Action,基本與Flux相同
b.定義reducers:我們常常看到的例子是這樣的
export default function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
或者是類似的變種吧。
3.Reducers原始碼分析
現在問題來了背後的資料流到底是如何產生的?還是看看原始碼吧。
export default function combineReducers(reducers) {
var reducerKeys = Object.keys(reducers)
var finalReducers = {}
for (var i = 0; i < reducerKeys.length; i++) {
var key = reducerKeys[i]
.......
return function combination(state = {}, action) {
...........
var hasChanged = false
var nextState = {}
for (var i = 0; i < finalReducerKeys.length; i++) {
var key = finalReducerKeys[i]
var reducer = finalReducers[key]
var previousStateForKey = state[key]
var nextStateForKey = reducer(previousStateForKey, action)
if (typeof nextStateForKey === 'undefined') {
var errorMessage = getUndefinedStateErrorMessage(key, action)
throw new Error(errorMessage)
}
nextState[key] = nextStateForKey
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
return hasChanged ? nextState : state
}
}
}
從原始碼中我們可以看到:在Redux中為了方便統一管理,省去了事件的繫結與解繫結,將事件作為事件佇列進行統一管理。
var reducerKeys = Object.keys(reducers)
var finalReducers = {}
for (var i = 0; i < reducerKeys.length; i++) {
var key = reducerKeys[i]
.....
}
每次執行一個事件操作時,並不僅僅只執行這個事件,而是會將事件佇列中的所有事件進行遍歷。
for (var i = 0; i < finalReducerKeys.length; i++) {
......
}
在每次遍歷時都在同一state上構建資料樹,同時在遍歷時會判斷本事件是否導致了整個state資料樹的資料變化。
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
return hasChanged ? nextState : state
......
}
看到這裡是否清楚了?好像還是沒有,Redux中的事件與資料流的管理,並不只是由一個函式完成的,而是由reducers、connect等多個函式共同完成,然而如此做法,對效能影響是否很大,這還得進一步檢視相關程式碼才能解惑。