Redux-saga详解

1,246 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情

一、什么是Redux-saga

Redux-saga是一个用于管理Redux异步操作的中间件,在saga中,全局监听器和接收器使用Generator函数和saga自身的一些辅助函数实现对整个流程的管控。其本质是一个可以自执行的Generator函数,它对异步操作进行集中管控处理,方便我们对于Redux异步流程的管控 流程:

二、Redux-saga是如何运行的

Redux-saga监听view视图层dispatch的action,判断是否是saga监测的action,如果是,将会执行异步任务,并利用Generato对异步任务同步化,最后dispatch新操作,从而改变redux中的state。

  • 监听用户发出的Action,并与自身监听Action做比对
  • 如果用户发出的Action是自己当前监听的Action,然后执行副作用(派发一个新的任务)。
  • reducer接收新任务,返回新数据并更新state。 Redux-saga流程图 1653926408569.jpg

三、实例操作

1.安装redux-saga

npm i redux-saga

2.新建文件

在src下新建redux-saga文件夹 1653926798904.jpg
(1) Main.js中视图层dispatch action

import React, { Component } from 'react'
import store from './redux/store'
export default class Main extends Component {
  render() {
    return (
      <div>
          <button onClick={()=>{
              store.dispatch({
                  type:'get-list'
              })
          }}>
               redux-sage
          </button>
      </div>
    )
  }
}

(2) reducer.js中存放我们对应action操作及数据

function reducer(preState={
    list:{}
},action={}){
    console.log(action)
    switch(action.type){
        case 'change-list':
            let newState={...preState}
            newState.list=action.payload
            return newState
        default:
             return preState
    }
}
export default reducer

(3) saga.js中执行监听操作

注意是从 redux-saga/effects引入take、fork、put、call方法(API使用请参考本文第四模块),该文件Generator使用较多,不了解同学建议回顾学习ES6该部分知识。
定义监听函数watchSaga,take方法用于监听组件发来的action,检测是否与自己匹配,fork函数同步处理异步函数。
在generator函数getList中,call函数用于执行并发送异步请求,其参数为promise对象的函数,在异步请求结束之后,使用put方法派发新任务并携带异步请求结果到reducer中,更新数据。注意此处getListAction函数是我们模仿异步请求的的promise对象,实际开发中是异步api请求。

import {take,fork,put,call} from 'redux-saga/effects'
function  *watchSaga(){
    while(true){
        // take函数只要有人发action就能监听到 监听组件发来的action
        // fork 同步处理异步函数
        yield take('get-list')
        yield fork(getList)
    }
}
// generator异步处理函数
function  *getList(){
    // call函数发送异步请求
    let res=yield call(getListAction) // 返回值是promise对象的函数
    // put 函数发出新的action
    yield put({
        type:"change-list",
        data:res
    })
}
function getListAction(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve(['111','222','333'])
        },2000)
    })
}
export default watchSaga

(4) store.js中创建实例

createSagaMiddleWare方法创建对象SagaNiddleWare后,放入中间件中,引入自定义的wacthSage方法,使用SagaNiddleWare.run方法运行saga监听

import {createStore,applyMiddleware} from 'redux'
import reducer from './reducer'

import createSagaMiddleWare from 'redux-saga'
const SagaNiddleWare =createSagaMiddleWare()
const store=createStore(reducer,applyMiddleware(SagaNiddleWare))

import watchSaga from './saga'
SagaNiddleWare.run(watchSaga) // saga监听

export default store

(5) 执行结果

我们在reducer中打印执行action,两秒钟之后会有新的派发任务接收到,并携带参数

1653925144738.jpg

四、核心API

(1)take

监听视图层传入的Action,检测是否与自身匹配,匹配则执行

function  *watchSaga(){
    while(true){
        // take函数只要有人发action就能监听到 监听组件发来的action
        yield take('get-list')
    }
}

(2)fork

异步非阻塞调用 在getList函数中,对于Ganerator来说, call函数需要执行异步请求,那么必须等待Promise异步请求执行结束并返回结果,call操作是阻塞的,而fork的作用是不必等待call函数执行完毕,不会影响接下来的其他任务的执行。

function  *watchSaga(){
    while(true){
         // fork 同步处理异步函数
        yield fork(getList)
    }
}

(3)call

异步阻塞调用 将异步函数作为第一个参数传入call函数中,等待异步请求执行结束,并返回res 个人认为类似async-awaite

 let res=yield call(getListAction) // 返回值是promise对象的函数

可以多次调用call函数处理多个异步请求函数,并能将上一个异步请求结果传递到下一个异步请求中

 let res1=yield call(getListAction1)
 let res2=yield call(getListAction2,res1)
 
 funtionc getListAction2(data){
 }

(4)put

相当于dispatch,推入新的Action到reducer中

 yield put({
        type:"change-list",
        data:res
    })

(5) tackEvery

每监听一次Action,匹配到Action便会执行一次

function  *watchSaga(){
    while(true){
        yield tackEvery('get-list')
    }
}

(6) takeLatest

监听匹配的Action,同时只执行最后一次匹配的Action,在此之前的异步请求将会停止。

function  *watchSaga(){
    while(true){
        yield tackEvery('get-list')
    }
}

(7)all([]...effects)

合并saga监听函数

import {all} from 'redux-saga/effects'
import watchSaga1 from './watchSaga1'
import watchSaga2 from './watchSaga2'
function  *watchSaga(){
    while(true){
        yield all([watchSaga1(),watchSaga2()])
    }
}
expory default watchSaga

五、总结

Redux-saga其实本身只是一个Redux中间件,使我们能够更优雅的管理Redux异步请求。它将异步请求从Action中抽离,使得Action更为纯粹,其次使用Generator对异步请求进行处理,更为方便以及易于管控。