redux-saga的简单使用——saga的模块化拆分——saga进行网络请求——同步修改状态

Posted 勇敢*牛牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了redux-saga的简单使用——saga的模块化拆分——saga进行网络请求——同步修改状态相关的知识,希望对你有一定的参考价值。

redux-saga

redux-saga 是 redux 一个中间件,它是基于ES6 的 Generator 功能实现,用于解决异步问题(让redux中可以直接进行异步操作)。


安装:

npm i -S redux-saga

项目中使用
store/sagas.js

// saga中间件 主saga,用于区别是否需要saga来处理异步操作,如果没有异步,则放行
function* mainSaga() 



// 监听saga,监听type类型为异步操作名称的,此saga会通过主saga分配过来
function* watchSaga() 



// 工作saga,监听saga得到任务后,把任务分配给工作saga
function* workSaga() 



export default mainSaga

三步走运行起来:saga

import  createStore,applyMiddleware  from "redux";
import  composeWithDevTools  from '@redux-devtools/extension'
import reducer from "@/store/reducer/index"


import mainSaga from "./sagas";
import createSagaMiddleware from "redux-saga";
const SagaMiddleware  = createSagaMiddleware()


const store = createStore(
    reducer,
    composeWithDevTools(applyMiddleware(SagaMiddleware))
)

// 运行saga
SagaMiddleware.run(mainSaga)
// 导出store
export default store

使用saga

获取数据

let num =  useSelector((store)=>
     console.log(store);//获取数据源
     return store.count.num
 )

发送dispatch

const dispatch = useDispatch()
const onclickHandler = ()=>
    dispatch(type:"asyncadd",payload:10)

  • takeEvery 监听每一次dispatch发送的指令
  • put 它是saga提供给我们,用于发送指令给reducer来完成同步操作
  • all方法,可以监听多个监听saga,它的功能和Promise.all方法一样,用在模块化


延迟触发查看是否能接受异步操作;

import takeEvery from "redux-saga/effects"
function delay(n=3)
    return new Promise((resolve)=>
        setTimeout(()=>
            resolve('')
        ,1000*n)
    )
 

function* mainSaga() 
    yield watchSaga()


function* watchSaga() 
    yield takeEvery('asyncadd', workSaga)


function* workSaga(payload) 
    /*收到发过的的dispatch */

    yield delay();//延时函数,看触发,模拟异步
    yield console.log(payload);
    yield put(type:"add",payload)


export default mainSaga


状态源:

const initState = 
    num :100


export default (state=initState,type,payload)=>
   if(type == "add")
        return ...state,num:state.num+payload
    
    return state


像上面的调用写法只能监听一个saga
这样的调用,它只能监听一个saga,不能进行模块化

  • all方法,可以监听多个监听saga,它的功能和Promise.all方法一样,用在模块化
import all from "redux-saga/effects"
import loginSaga from "./watchsaga/login"

function* mainSaga() 
    yield all([
        loginSaga()
    ])


export default mainSaga

拆分这个监听saga函数

import takeEvery,put from "redux-saga/effects"
function delay(n=1)
    return new Promise((resolve)=>
        setTimeout(()=>
            resolve('')
        ,1000*n)
    )
 

function* watchSaga() 
    yield takeEvery('asyncadd', addSaga)
    //可以写多个


function* addSaga(payload) 
    /*收到发过的的dispatch */
    yield delay();//延时函数,看触发,模拟异步,完成网络请求
    yield console.log(payload);
    yield put(type:"add",payload)


export default watchSaga

saga进行网络请求

这里就有个参数必须得使用:
call方法,调用Promise对象
第一个参数是函数名,而不是去执行函数,后面跟着的就是参数

import takeEvery,put,call from "redux-saga/effects"
import post from "@/utils/http"
function* watchSaga() 
    yield takeEvery('asyncadd', addSaga)


/* 在此处完成网络请求 */
function* addSaga(payload) 
    /*收到发过的的dispatch saga帮我们实现了这个co赋值过程*/
    let ret = yield call(post,payload)
    if(ret.code == 200)
        yield put(type:"loginadd",payload:ret.data)//全局更新登录信息
    

export default watchSaga

实地测试模拟异步的状态变化,引起视图的改变。

import takeEvery,put,call from "redux-saga/effects"
function delay(n=2)
    return new Promise((resolve)=>
        setTimeout(()=>
            resolve(code:200,data:"ok")
        ,1000*n)
    )
 

function* watchSaga() 
    yield takeEvery('asyncadd', addSaga)


/* 在此处完成网络请求 */
function* addSaga(payload) 
    /*收到发过的的dispatch */
    let ret = yield call(delay,5)
    console.log(ret);
    if(ret.code == 200)
         yield put(type:"loginadd",payload:data:ret.data)//全局更新登录信息
    
    

export default watchSaga

两种跳转路由的方式:

思路一:hack登录状态成功,在 修改dispatch之后就把state修改,同步修改之后,直接在redux中获取判断,是否需要跳转。
或者:
进行登录,dispatch是它是一个异步的,交给saga,saga会完成异步操作,通知reducer完成同步修改redux中的state数据改变, reducer把state中的数据修改后,因为我在当前的组件中有通过useEffect来依赖此state中的值的变化,所以它只要变化了,我就可以来跳转,从而可以确认redux中的数据一定是存在后才跳转的


因为:generator的返回值,不是普通函数这样的返回值,这样在登录成功后,无法让前端的组件完成路由的切换,切换的原则是登录成功后,才能能跳转,登录的过程它是一个异步的,所以此时工作就有点难受。说白了,在使用thunk中间件时,异步hook函数useDispatch的dispatch方法之后会有普通函数的返回值,而使用saga中间件,generator的返回值就不能使用。


思路二:使用插件


安装

connected-react-router

在接收到异步数据之后, 在redux中成功后的路由跳转。

以上是关于redux-saga的简单使用——saga的模块化拆分——saga进行网络请求——同步修改状态的主要内容,如果未能解决你的问题,请参考以下文章

redux-saga

手写Redux-Saga源码

为啥使用 redux-thunk 或 redux-saga 进行 fetches?

Declarative Effects --- redux-saga

多个 redux-sagas

redux-saga基本用法