1. 程式人生 > >React實戰-深入原始碼瞭解Redux用法之Reducers

React實戰-深入原始碼瞭解Redux用法之Reducers

React實戰-深入原始碼瞭解Redux用法之Reducers

ReduxReducers是真正實現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等多個函式共同完成,然而如此做法,對效能影響是否很大,這還得進一步檢視相關程式碼才能解惑。