Redux
源码解读 - bindActionCreators
篇(完结)
bindActionCreators
这个函数的主要作用,就是包装action
的创建,并且和dispatch
进行结合
可以举个例子来看看它的用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| const reducer = (state = { val: 10 }, action) => { switch (action.type) { case "increment": return { ...state, val: state.val + action.val, }; case "decrement": return { ...state, val: state.val - action.val, }; default: return state; } };
const store = createStore(reducer);
const incrementAction = (val) => { return { type: "increment", val, }; };
const decrementAction = (val) => { return { type: "decrement", val, }; };
const execAction = bindActionCreators( { incrementAction, decrementAction, }, store.dispatch );
console.log(execAction);
store.subscribe(() => { console.log(`当前state:${store.getState().val}`); });
execAction.incrementAction(10); execAction.decrementAction(5);
|
运行之后就可以看到效果:
通过包装,可以以一个函数来完成action
的创建和分发。
在中文文档中,指出来这样做的好处(结合React
)。
惟一会使用到bindActionCreators
的场景是当你需要把action creator
往下传到一个组件上,却不想让这个组件觉察到Redux
的存在,而且不希望把dispatch
或Redux store
传给它。
意思上大致是,对于一个纯组件,不应该明确地感知到Redux
,通过bindActionCreators
包装可以向纯组件传入一个函数来完成功能,而不是在纯组件中使用到dispatch
函数和action
对象。
ok,先贴上源码,其实这个函数并不难,比前面三个容易理解多了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| export default function bindActionCreators(actionCreators, dispatch) { if (typeof actionCreators === "function") { return bindActionCreator(actionCreators, dispatch); }
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"?` ); }
const boundActionCreators = {}; for (const key in actionCreators) { const actionCreator = actionCreators[key]; if (typeof actionCreator === "function") { boundActionCreators[key] = bindActionCreator(actionCreator, dispatch); } } return boundActionCreators; }
|
这个函数支持两种传入的方式,一种是传入一个函数,一种是传入一个对象,这个对象的键的值为一个函数。
即在例子中的代码:
1 2 3 4 5 6 7
| const execAction = bindActionCreators( { incrementAction, decrementAction, }, store.dispatch );
|
可以写为
1 2
| const execIncrementAction = bindActionCreators(incrementAction, store.dispatch); const execDecrementAction = bindActionCreators(decrementAction, store.dispatch);
|
这两者的效果完全一样。
1 2 3
| if (typeof actionCreators === "function") { return bindActionCreator(actionCreators, dispatch); }
|
函数开始的判断就是对应第一种情况,只传入一个函数。
可以看到直接返回了一个bindActionCreator
的函数。
1 2 3 4 5
| function bindActionCreator(actionCreator, dispatch) { return function () { return dispatch(actionCreator.apply(this, arguments)); }; }
|
这个函数也非常的简单,返回了一个函数,这个函数就是dispatch
一个action
。
而action
参数通过传入的actionCreator
函数来创建。
传入actionCreator
的参数就是返回函数的参数列表。
也就是:
1
| execAction.incrementAction(10);
|
接下来又进行了一次判断:
1 2 3 4 5 6 7 8
| 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"?` ); }
|
如果不是object
或者传了个空进来的话,直接报错。
1 2 3 4 5 6 7
| const boundActionCreators = {}; for (const key in actionCreators) { const actionCreator = actionCreators[key]; if (typeof actionCreator === "function") { boundActionCreators[key] = bindActionCreator(actionCreator, dispatch); } }
|
最后这段代码就对应第二种情况,传入一个对象。
通过for-in
循环,把值为函数的挑出来,然后使用第一种情况,存在一个boundActionCreators
对象里。
最后返回boundActionCreators
对象。
这个函数就是这么通俗易懂。
至此Redux
的源码已经讲完啦。
个人感觉上还行,基本上都能搞懂。