天天看點

redux-saga的簡單使用——saga的子產品化拆分——saga進行網絡請求——同步修改狀态

redux-saga

redux-saga 是 redux 一個中間件,它是基于ES6 的 Generator 功能實作,用于解決異步問題(讓redux中可以直接進行異步操作)。

redux-saga的簡單使用——saga的子產品化拆分——saga進行網絡請求——同步修改狀态

安裝:

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      

三步走運作起來: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      

使用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方法一樣,用在子產品化
redux-saga的簡單使用——saga的子產品化拆分——saga進行網絡請求——同步修改狀态

延遲觸發檢視是否能接受異步操作;

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      
redux-saga的簡單使用——saga的子產品化拆分——saga進行網絡請求——同步修改狀态

狀态源:

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      

拆分這個監聽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      

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      

實地測試模拟異步的狀态變化,引起視圖的改變。

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      

兩種跳轉路由的方式:

思路一: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