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-thunk 或 redux-saga 进行 fetches?