Redux源码解读 - bindActionCreators篇(完结)
Redux源码解读 - bindActionCreators篇(完结)
bindActionCreators 🔗
这个函数的主要作用,就是包装action的创建,并且和dispatch进行结合
可以举个例子来看看它的用法
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,
};
};
// action创建函数和dispatch结合
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,先贴上源码,其实这个函数并不难,比前面三个容易理解多了。
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;
}这个函数支持两种传入的方式,一种是传入一个函数,一种是传入一个对象,这个对象的键的值为一个函数。
即在例子中的代码:
const execAction = bindActionCreators(
{
incrementAction,
decrementAction,
},
store.dispatch
);可以写为
const execIncrementAction = bindActionCreators(incrementAction, store.dispatch);
const execDecrementAction = bindActionCreators(decrementAction, store.dispatch);这两者的效果完全一样。
if (typeof actionCreators === "function") {
return bindActionCreator(actionCreators, dispatch);
}函数开始的判断就是对应第一种情况,只传入一个函数。
可以看到直接返回了一个bindActionCreator的函数。
function bindActionCreator(actionCreator, dispatch) {
return function () {
return dispatch(actionCreator.apply(this, arguments));
};
}这个函数也非常的简单,返回了一个函数,这个函数就是dispatch一个action。
而action参数通过传入的actionCreator函数来创建。
传入actionCreator的参数就是返回函数的参数列表。
也就是:
execAction.incrementAction(10); //这里的10就会传给actionCreator函数接下来又进行了一次判断:
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或者传了个空进来的话,直接报错。
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的源码已经讲完啦。
个人感觉上还行,基本上都能搞懂。
