React/Redux中switch分支与default抛出错误的拦截行为差异
Redux Reducer与中间件错误处理的差异解析
咱们先把你的代码摆出来,再一步步拆解问题:
初始版本的Reducer与中间件
const reducer = ( state = { username : '', token : '?' }, action ) => { switch (action.type){ case 'SET_TOKEN': state = { ...state, token : action.payload } break case 'SET_USERNAME': state = { ...state, username : action.payload } break case 'SET_USERNME': throw new Error("Errore, nessuna azione corrispondente") break } return state } const logger = (store) => (next) =>(action) => { console.log(store, next, action); next(action); } const error = (store) => (next) =>(action) => { try{ console.log("Checking errors"); next(action); }catch(e){ console.log("Error is: " +e); } } const middleware = applyMiddleware(logger, error);
当你派发SET_USERNME这个action时,控制台会打印错误但应用还能正常跑,核心原因在于中间件的执行顺序和错误捕获逻辑:
- Redux中间件是按
applyMiddleware里的顺序从左到右执行的:先跑logger,再跑error,最后才到reducer。 - 当
logger调用next(action),会把action传给error中间件;error里的next(action)会把action传给reducer。 - reducer匹配到
SET_USERNME分支后抛出错误,这个错误会立刻被error中间件的try/catch捕获,控制台打印错误信息,但错误不会向上冒泡到应用的其他部分,Redux会保持原有状态,所以应用不会崩溃。
修改后的Reducer版本
switch (action.type){ case 'SET_TOKEN': state = { ...state, token : action.payload } break case 'SET_USERNAME': state = { ...state, username : action.payload } break default: throw new Error("Errore, nessuna azione corrispondente") break }
现在来说两种写法的核心差异:
1. 错误触发的范围不同
- 第一种写法:只有当action.type严格等于
SET_USERNME时才会抛错,其他未匹配的action(比如随便写一个SET_XXX)会跳出switch,执行最后的return state,返回原状态,不会触发任何错误。 - 第二种写法:所有未匹配到
SET_TOKEN/SET_USERNAME的action都会触发错误,不管是SET_USERNME还是其他任意未定义的action类型,都会进入default分支抛错,覆盖的范围要大得多。
2. Reducer的返回逻辑差异
- 第一种写法:当触发
SET_USERNME抛错时,reducer函数会立刻终止,不会执行最后的return state;但因为错误被中间件捕获,Redux不会使用这个未完成的执行结果,而是维持之前的状态。 - 第二种写法:触发default分支抛错时,同样会终止reducer的执行,没有返回值,但错误同样被
error中间件捕获,Redux依旧保持原有状态,应用也不会崩溃。
本质上两种情况应用都能正常运行的原因是一样的:你的error中间件刚好在reducer之前执行,把reducer抛出的所有异常都拦截并处理了,阻止了错误影响到应用的其他逻辑。
内容的提问来源于stack exchange,提问作者DxW
相关产品推荐
相关产品推荐

