标准答案

  1. Redux reducer 必须保持纯函数,异步请求、日志、埋点等副作用应放在中间件或外部逻辑中。
  2. 中间件通过包装 dispatch 形成链式调用,可以在 action 到达 reducer 前后执行额外逻辑。
  3. Thunk 允许 dispatch 一个函数,在函数里拿到 dispatch 和 getState,适合简单异步请求。
  4. Saga 使用 generator 描述副作用流程,适合复杂编排、取消、并发、节流和长事务。
  5. Thunk 简单直接,Saga 表达能力强但概念成本更高。

题目解析

这道题可以从“Redux 本身只管理同步状态变更”讲起。中间件是副作用进入 Redux 流程的入口。

Thunk 更像把异步逻辑写成普通函数,学习成本低;Saga 更像声明一套可测试、可取消的流程。

如果项目异步逻辑只是普通 CRUD,Thunk 或 RTK Query 往往已经够用;复杂业务流程才更需要 Saga。

代码示例

下面的 Thunk 在请求成功后派发 fulfilled action。

TypeScript
export const loadUser = (id: string) => async (dispatch: AppDispatch) => {
  dispatch(userActions.loading())

  try {
    const user = await fetchUser(id)
    dispatch(userActions.loaded(user))
  } catch (error) {
    dispatch(userActions.failed(normalizeError(error)))
  }
}

常见误区

  • 在 reducer 里发请求或写副作用,破坏 Redux 可预测性。
  • 简单请求也引入 Saga,增加没有必要的心智负担。
  • 异步 action 没有统一错误结构,页面无法稳定处理失败状态。

作者信息