React+Redux之bindactioncreators的用法

weixin_33670713發表於2018-07-11
12693563-8451dc957bf0a4a9.png

上面程式碼我們可以看到是呼叫了bindActionCreators方法把action繫結到了connect方法中,其中connect方法的作用是連線react元件和redux store,也就是說通過connect方法子元件可以獲取store中的state和dispatch。

感覺還是沒找到在哪呼叫的dispatch方法,所以把注意力集中在bindActionCreators方法中,搜了下看到一些解釋:bindActionCreators的作用是將一個或多個action和dispatch組合起來生成mapDispatchToProps需要生成的內容。
看程式碼:

不使用bindActionCreators時候:

let actions = {
  onIncrement :  {
    type: types.ADD_ITEM,
    text
  }
}
function mapDispatchToProps(dispatch) {
   return {
         onIncrement: (...args) => dispatch(actions.onIncrement(...args)),
  }
}

使用時:

let actions = {
  onIncrement :  {
    type: types.ADD_ITEM,
    text
  }
}
function mapDispatchToProps(dispatch) {
    return bindActionCreators({ actions.onIncrement }, dispatch);
}

bindActionCreator 的作用其實就是用來將一個物件的值是action creators轉成一個同樣key的物件,但是轉化的這個物件的值,是將action creator包裹在dispatch裡的函式。
也就是說,假設下面的actionCreator.js 我們import進來這個物件

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

export function removeTodo(id) {
  return {
    type: 'REMOVE_TODO',
    id
  }
}

得到的物件為

{
   addTodo : text => 
    { 
      type: 'ADD_TODO',
      text
    },
   removeTodo : id => {
      type: 'REMOVE_TODO',
      id
    }
}

經過bindActionCreator就會變成

{
   addTodo : text => dispatch(addTodo('text'));
   removeTodo : id => dispatch(removeTodo('id'));
}

相當於會dispatch這個action

引數:
1、actionCretors 可以是一個物件,也可以是一個單個函式
2、dispatch函式

返回:
單個函式,或者是一個物件。

傳入一個function
如果只是傳入一個function,返回的也是一個function

例如:

const toggleTodo = (id) => {
    return {
        type: 'TOGGLE_TODO',
        id
    };
};

export { toggleTodo };
let boundActionCreators = bindActionCreators(toggleTodo, dispatch);

//此時boundActionCreators  = (id) => dispatch(toggleTodo(id));

所以bindActionCreator比較簡單:
1、判斷傳入的引數是否是object,如果是函式,就直接返回一個包裹dispatch的函式
2、如果是object,就根據相應的key,生成包裹dispatch的函式即可

bindActionCreators原始碼解析

function bindActionCreator(actionCreator, dispatch) {
  // 這個函式的主要作用就是返回一個函式,當我們呼叫返回的這個函式的時候,就會自動的dispatch對應的action
  // 這一塊其實可以更改成如下這種形式更好
  // return function(...args) {return dispatch(actionCreator.apply(this, args))}
  return function() { return dispatch(actionCreator.apply(this, arguments)) }
}
/**
    引數說明: 
        actionCreators: action create函式,可以是一個單函式,也可以是一個物件,這個物件的所有元素都是action create函式
        dispatch: store.dispatch方法
*/
export default function bindActionCreators(actionCreators, dispatch) {
  // 如果actionCreators是一個函式的話,就呼叫bindActionCreator方法對action create函式和dispatch進行繫結
  if (typeof actionCreators === 'function') {
    return bindActionCreator(actionCreators, dispatch)
  }
  // actionCreators必須是函式或者物件中的一種,且不能是null
  if (typeof actionCreators !== 'object' || actionCreators === null) {
    throw new Error(
      `bindActionCreators expected an object or a function, instead received ${actionCreators === null ? 'null' : typeof actionCreators}. ` +
      `Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?`
    )
  }

  // 獲取所有action create函式的名字
  const keys = Object.keys(actionCreators)
  // 儲存dispatch和action create函式進行繫結之後的集合
  const boundActionCreators = {}
  for (let i = 0; i < keys.length; i++) {
    const key = keys[i]
    const actionCreator = actionCreators[key]
    // 排除值不是函式的action create
    if (typeof actionCreator === 'function') {
      // 進行繫結
      boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
    }
  }
  // 返回繫結之後的物件
  /**
      boundActionCreators的基本形式就是
      {
      actionCreator: function() {dispatch(actionCreator.apply(this, arguments))}
      }
  */
  return boundActionCreators
}

相關文章