Redux 的数据流和中间件原理是什么?redux-thunk 和 redux-saga 有什么区别?

先理解原理和示例,再练习完整口述与追问。

单向数据流:dispatch(action) → reducer(state, action) 纯函数返回新状态 → store 通知订阅者。中间件是包装 dispatch 的柯里化函数 store => next => action,可在 action 到达 reducer 前处理异步、日志等。thunk 允许 dispatch 函数,简单直接;saga 用 Generator 描述副作用,适合复杂流程编排。现代项目推荐 Redux Toolkit。

reducer 必须纯净且不可变地更新状态,才能让订阅者通过引用比较判断是否变化,也支持时间旅行调试。applyMiddleware(...middlewares) 把中间件从右到左组合,每个中间件拿到 next(下一个中间件包装后的 dispatch),最终的 next 是原始 dispatch。

redux-thunk 检查 action 是否为函数,是则调用它并传入 dispatch 和 getState;saga 则监听 action,用 call、put、takeLatest、race 等 effect 描述副作用,Generator 让测试只需比对 effect 对象。Redux Toolkit 的 createSlice 内置 Immer,可以写“看似可变”的代码;createAsyncThunk 处理异步,RTK Query 负责请求缓存。

js
const thunk = ({ dispatch, getState }) => next => action =>
  typeof action === 'function' ? action(dispatch, getState) : next(action)

const logger = store => next => action => {
  const result = next(action)
  console.log(action.type, store.getState())
  return result
}

调用 dispatch(fetchUser(1)),若 fetchUser 返回函数,thunk 拦截并执行它,内部完成请求后再 dispatch({ type: 'user/loaded', payload }) 进入 reducer。

在 reducer 中发请求或生成随机数破坏纯函数约定;直接修改 state 后返回同一引用,组件不会更新。把所有状态都放进 Redux,会让表单输入等局部状态变得笨重。

Redux 是单向数据流:组件 dispatch action,reducer 纯函数根据旧状态和 action 返回新状态,store 再通知订阅者更新。中间件是 store => next => action 形式的柯里化函数,层层包装 dispatch,在 action 到达 reducer 之前做异步、日志等处理。thunk 让 dispatch 可以接收函数,适合简单异步;saga 用 Generator 描述副作用,适合取消、竞态这类复杂流程。新项目我会直接用 Redux Toolkit,服务端数据用 RTK Query 或 React Query。