Redux 中间件作用(redux-thunk/redux-saga)

Redux 中间件(Middleware)本质上是:
dispatch(action) 到达 reducer 之前,对 action 做增强处理的一层机制。

它主要解决:

  • 异步请求
  • 日志打印
  • 权限校验
  • 接口调用
  • 延迟 dispatch
  • 副作用管理

一、Redux 默认的问题

Redux 原生规定:

bash 复制代码
store.dispatch({
  type: 'ADD'
})

dispatch 只能发送:

  • 普通对象 action

而且:

  • reducer 必须是纯函数
  • reducer 不能写异步

所以:

scss 复制代码
setTimeout()
axios()
fetch()

这些都不能直接写进 reducer。

这时候就需要:

中间件 Middleware


二、中间件执行流程

Redux 数据流:

scss 复制代码
dispatch(action)
   ↓
middleware
   ↓
reducer
   ↓
store 更新
   ↓
view 更新

多个中间件:

复制代码
dispatch
  ↓
thunk
  ↓
logger
  ↓
saga
  ↓
reducer

三、redux-thunk

1. thunk 是什么

Redux Thunk

Thunk 是 Redux 最常用的异步中间件。

它允许:

scss 复制代码
dispatch(function)

而不是只能:

scss 复制代码
dispatch(object)

四、redux-thunk 核心思想

普通 Redux:

bash 复制代码
dispatch({
  type: 'GET_USER'
})

Thunk:

csharp 复制代码
dispatch(async function(dispatch){
   const res = await axios.get('/user')

   dispatch({
      type:'SET_USER',
      payload: res.data
   })
})

也就是:

dispatch 一个函数

函数内部:

  • 可以写异步
  • 可以再次 dispatch
  • 可以拿到 store

五、thunk 工作原理

内部核心思想:

javascript 复制代码
const thunk = store => next => action => {

   if(typeof action === 'function'){
      return action(store.dispatch, store.getState)
   }

   return next(action)
}

意思:

  • 如果 dispatch 的是函数

    • 就执行它
  • 如果是普通对象

    • 继续传给 reducer

六、thunk 使用流程

1. 安装

复制代码
npm install redux-thunk

2. 注册 middleware

javascript 复制代码
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'

const store = createStore(
  reducer,
  applyMiddleware(thunk)
)

3. 编写异步 action

dart 复制代码
export const getUser = () => {

  return async (dispatch) => {

    const res = await axios.get('/api/user')

    dispatch({
      type:'SET_USER',
      payload:res.data
    })
  }
}

4. 页面调用

scss 复制代码
dispatch(getUser())

七、redux-thunk 优缺点

优点

简单易学

适合:

  • 小项目
  • 中型项目
  • 简单异步

缺点

大型项目容易:

  • 回调地狱
  • action 逻辑混乱
  • 难维护
  • 副作用分散

例如:

scss 复制代码
dispatch(async ()=>{
   await api1()
   await api2()
   await api3()
})

会越来越复杂。


八、redux-saga

Redux-Saga

Saga 是:

更强大的异步流程管理方案

核心思想:

复制代码
把异步逻辑单独管理

类似:

  • 后台任务
  • 事件监听
  • 协程
  • generator

九、saga 最大特点

它使用:

javascript 复制代码
Generator

例如:

php 复制代码
function* getUserSaga() {

   const res = yield call(api.getUser)

   yield put({
      type:'SET_USER',
      payload:res
   })
}

十、saga 工作流程

scss 复制代码
dispatch(action)
    ↓
saga监听
    ↓
执行异步任务
    ↓
put(action)
    ↓
reducer

十一、核心 API

takeEvery

监听每次 action

java 复制代码
yield takeEvery('GET_USER', getUserSaga)

takeLatest

只保留最后一次请求

适合搜索:

java 复制代码
yield takeLatest('SEARCH', searchSaga)

put

等于 dispatch

java 复制代码
yield put({
  type:'SET_USER'
})

call

调用异步函数

java 复制代码
yield call(api.getUser)

select

获取 store 数据

csharp 复制代码
const state = yield select()

十二、saga 使用流程

1. 安装

复制代码
npm install redux-saga

2. 创建 sagaMiddleware

javascript 复制代码
import createSagaMiddleware from 'redux-saga'

const sagaMiddleware = createSagaMiddleware()

3. 注册

ini 复制代码
const store = createStore(
  reducer,
  applyMiddleware(sagaMiddleware)
)

4. 启动 saga

scss 复制代码
sagaMiddleware.run(rootSaga)

5. 编写 saga

javascript 复制代码
function* getUserSaga(){

   const res = yield call(api.getUser)

   yield put({
      type:'SET_USER',
      payload:res
   })
}

function* rootSaga(){
   yield takeEvery('GET_USER', getUserSaga)
}

十三、thunk vs saga

对比 thunk saga
学习成本
异步方式 函数 Generator
复杂流程 一般
维护性
适合项目 小中型 大型
取消请求 不方便 容易
并发控制
副作用管理 分散 集中

十四、实际项目怎么选

小项目

直接:

  • Redux Toolkit
  • thunk

现在主流:

Redux Toolkit

因为 RTK 默认内置 thunk。


大型项目

复杂场景:

  • websocket
  • mqtt
  • 长连接
  • 多请求编排
  • 权限流
  • 工作流

适合:

  • saga

十五、你现在前端开发里更应该学什么

结合你现在 React + 平台开发经验:

建议优先级:

markdown 复制代码
Redux Toolkit
    ↓
RTK Query
    ↓
redux-thunk
    ↓
redux-saga

因为现在很多公司:

  • 已经不用传统 redux
  • 更偏 RTK

十六、现代 Redux 已经变成这样

以前:

复制代码
redux
redux-thunk
action
reducer
constants
types

现在:

复制代码
Redux Toolkit
createSlice
createAsyncThunk
RTK Query

代码量减少很多。


十七、现代写法(推荐)

dart 复制代码
import { createAsyncThunk } from '@reduxjs/toolkit'

export const getUser = createAsyncThunk(
  'user/getUser',
  async ()=>{

     const res = await axios.get('/user')

     return res.data
  }
)
相关推荐
2601_9657984719 分钟前
Arrow Unlocker HTML5 Game Review: Keep Web Arcade Players Coming Back
前端·html·html5
不简说1 小时前
JS 代码技巧 vol.10 — 20 个 V8 引擎原理,解释"为什么这样写快"
前端·javascript·面试
醉城夜风~1 小时前
HTML常用标签详解学习博客:从基础标签到页面结构完整掌握
前端·学习·html
OpenTiny社区1 小时前
拒绝臃肿!TinyRobot从“AI 输入框”到“AI输入控制台”的可扩展进化
前端·vue.js
淼澄研学2 小时前
PyTorch深度学习实战:5个核心方法从0到1构建神经网络
前端·数据库·python
MartinYeung52 小时前
[论文学习]WASP:面向提示注入攻击的Web代理安全性基准测试
前端·网络·学习
lemon_sjdk2 小时前
从 ServletRequest 到 Spring 抽象:Web 请求的底层基石与演化
java·前端·spring
程序员黑豆3 小时前
鸿蒙应用开发之状态变化通知:@Watch 装饰器详解与实战
前端·harmonyos
swipe3 小时前
13|(前端转全栈)支付成功不等于结束:回调、幂等、超时关单和状态竞争
前端·后端·面试
swipe3 小时前
12|(前端转全栈)点击提交订单后,后端如何用事务守住价格、库存和订单?
前端·后端·面试