1. 程式人生 > >Redux原始碼解讀 [03] 之 bindActionCreators

Redux原始碼解讀 [03] 之 bindActionCreators

回顧 actionCreator

接下來說說 bindActionCreators 這個方法,bindActionCreators 不難理解,但在此之前需要回顧一下我們之前講到的 actionCreator 的概念,我們知道,要更新state樹的唯一途徑是發起一個action,如:

dispatch({
    type: 'ADD_TODO',
    text: 'ADD TODO AGAIN.' 
})

每個action都需要寫type,這樣每次寫起來就會覺得冗餘,於是產生了 actionCreator 的概念,我們寫一個函式,幫我們寫好指定的type,傳入不同的資訊載荷就可以了,如:

function addTodo(text){
    return{
         type: 'ADD_TODO',
         text
    }
}

上面就是一個actionCreator 的例子,注意actionCreator 和action是兩個不同的概念,action是物件,用來描述state發生了什麼變化,而actionCreator 是函式,是用來生成action的工廠。

bindActionCreator 函式

再然後來看看bindActionCreators 方法用到的一個函式:

function bindActionCreator(actionCreator, dispatch)
{
return function() { return dispatch(actionCreator.apply(this, arguments)) } }

函式的兩個引數:
* actionCreator 函式,用於生產action的工廠
* dispatch 函式,也就是Store.dispatch ()

函式非常簡單,也就是將 dispatch 和 actionCreator 繫結返回一個新的函式,使用這個函式時會直接 dispatch 一個 action,變得更加簡便,如:

let actionCreator = (text)=>({
     type: 'ADD_TODO,
     text
})

let addTodo = bindActionCreator(actionCreator , Store.dispatch)
// 呼叫
addTodo('
ADD SOMETHING’) // 等價於: dispatch({ type: 'ADD_TODO', text: 'ADD SOMETHING' })

也就是說 actionCreator 幫我們省略了重複書寫action.type , bindActionCreator 幫我們省略了重複書寫 dispatch,而且還可以隱藏 dispatch 引數。再來看看bindActionCreators方法就不難理解了:

bindActionCreators 方法

export default function bindActionCreators(actionCreators, dispatch) {

  // 如果傳入的actionCreators是一個函式,則直接繫結返回一個新的函式
  if (typeof actionCreators === 'function') {
    return bindActionCreator(actionCreators, dispatch)
  }
  // 如果傳入的actionCreators是Object型別 
  // Object的欄位都是一個個 actionCreator
  if (typeof actionCreators !== 'object' || actionCreators === null) {
    throw new Error(
      `xxxx`
    )
  }

  const keys = Object.keys(actionCreators) // 所有的key
  const boundActionCreators = {} // 最終返回的物件

  for (let i = 0; i < keys.length; i++) {
    const key = keys[i]
    const actionCreator = actionCreators[key]
    // 過濾不合法的值 逐一進行繫結
    if (typeof actionCreator === 'function') {
      boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
    }
  }
  //返回最終繫結好 actionCreator 物件
  return boundActionCreators
}

最後

總結一下 bindActionCreators 方法,首先引數dispatch是必須的,也就是Store.dispatch()。
* 如果你傳入的 actionCreators 引數僅僅是一個 actionCreator 函式,那麼直接繫結 actionCreator 和 dispatch,返回一個新函式,呼叫函式傳入action的載荷,就可以直接發起一個指定type的action。
* 如果你傳入的 actionCreators 引數是一個物件,那麼物件的欄位必須是一個個actionCreator函式,返回一個物件,物件逐一進行繫結,每個欄位都是繫結好的函式,呼叫它們傳入action的載荷,就會直接發起一個指定type的action。

使用場景

Redux文件上關於何時使用到此API是這樣說的:
惟一會使用到 bindActionCreator 的場景是當你需要把 action creator 往下傳到一個元件上,卻不想讓這個元件覺察到 Redux 的存在,而且不希望把 dispatch 或 Redux store 傳給它。