redux源码分析:dispatch中为什么需要 isDispatching
同步函数中,出现 isDispatching 的意义何在
先说重点,下面是源码里的结论
不要在 reducer 里执行 store.dispatch: Reducers may not dispatch actions.
自己的看法
- reducer 里不要有
store.dispatch
有了isDispatching
就杜绝了reducer
里的各种”骚“操作的出现,从性能/BUG
两方面都有好处 - 针对 store.dispatch 这个情况,我看到一种说法: 你可以把检查isDispatching理解为一种约束声明
- 为什么要做这种限制 ,因为实际中的
disaptch actions
很多,不知情的情况下就会写出那种循环dispatch
的代码,虽然限制之后会带来很多的不便
认同的观点
我基(cong)本(lai)不用redux,不过根据问题描述来看,这是为了防止重入。
这和单线程、纯函数没有关系。『之前的 reducer 肯定是已经执行完毕了』只是良好的愿望,实际上可能被违反。而加上这检查就可以在万一玩脱了的时候扔个异常给你冷静一下。
你可以把检查isDispatching理解为一种约束声明(类似于一些语言里的assert断言)。
想从代码层面就杜绝2种情况的出现
- 用户在reducer中错误地调用了dispatch,从而再次使reducer被调用,进而造成死循环
- 用户在reducer中错误地调用了dispatch,从而再次使reducer被调用,A→B→C→D→E… 不一定死循环,但链路特别长
看代码:如果没有 isDispatching
,用户就有可能写出这样的代码
const reducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
store.dispatch({ type: 'ANY' });
return state + 1;
case 'DECREMENT':
return state - 1;
case 'ANY':
store.dispatch({ type: 'INCREMENT' });
return state;
default:
return state;
}
};
已经作死的调了一下,先手动删除了 isDispatching
的这段控制逻辑 : dispatch({ type: “ANY"})
,现象如下: RangeError: Maximum call stack size exceeded
几个关于这个问题的讨论
先看一下这段代码 redux@3.7.2
function dispatch(action) {
// 无情的省略号...
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.');
}
try {
isDispatching = true;
currentState = currentReducer(currentState, action);
} finally {
isDispatching = false;
}
// 无情的省略号...
return action;
}