当前位置: 首页 > Web前端 > HTML5

redux-saga框架详解及demo教程

时间:2023-04-05 21:39:39 HTML5

redux-saga框架详解及demo教程之前我们已经讲解了redux框架和dva框架的基本使用,因为dva框架中的effects模块是针对知识点设计的在redux-saga中,可能有同学使用dva框架,但是对redux-saga不是很熟悉。今天我们就来简单介绍一下saga框架的主要API,以及redux框架如何使用redux-saga。官方地址http://leonshi。com/redux-saga-in-chinese/index.htmlDemo运行效果图todoListCounterApp示例Demo地址redux-saga-Demo作者还是沿用了之前的风格,提供了两个不同的版本,简单的CounterApp和稍微复杂一点的TodoListCounterApphttps://github.com/guangqiang-liu/redux-saga-counterApptodoListhttps://github.com/guangqiang-liu/redux-saga-todoListDemo什么是redux-sagaredux-saga是一个管理Redux应用异步操作的中间件(又名异步操作)。redux-saga通过创建Sagas将所有异步操作逻辑集中在一个地方,可以用来替代redux-thunk中间件。这意味着应用程序的逻辑将存在于两个地方:Reducers负责处理动作的状态、更新Sagas以及协调那些复杂或异步的操作。GeneratorSagas介绍不同于thunks,thunks是在创建action的时候调用的,而Sagas只有在应用启动的时候才会被调用(但是最开始启动的Sagas可能会动态调用其他的Sagas),Sagas可以看做是运行在后台进程中,Sagas监听发起的action,然后根据这个action决定做什么:是发起异步调用(比如fetchrequest),还是向Store发起其他action,甚至调用redux世界中的其他Sagas-saga中,所有的任务都是通过yieldEffects来完成的(Effect可以看作是redux-saga的任务单元)。Effects是简单的Javascript对象,包含了Saga中间件要执行的信息(比如可以看到Redux的action其实就是包含执行信息的对象),redux-saga提供了各种Effectcreator,比如调用异步函数,发起action到Store,启动一个后台任务或者等待满足一定条件的未来动作用于在向Store发起一些特定的动作时派生任务。先解释一下两个辅助函数:takeEvery和takeLatesttakeEvery。例如:每次单击Fetch按钮时,我们都会启动一个FETCH_REQUESTED操作。我们想通过启动一个任务从服务器获取一些数据来处理这个动作首先我们创建一个任务来执行异步动作:import{call,put}from'redux-saga/effects'exportfunction*fetchData(action){尝试{constdata=yieldcall(Api.fetchUser,action.payload.url);yieldput({type:"FETCH_SUCCEEDED",data});}catch(error){yieldput({type:"FETCH_FAILED",error});}}然后在每次启动FETCH_REQUESTED动作时启动上面的任务下面替换function*watchFetchData(){while(true){yieldtake('FETCH_REQUESTED');产量叉(fetchData);}}takeLatest在上面的例子中,takeEvery允许多个fetchData实例同时启动,在某个时刻,我们可以启动一个新的fetchData任务,尽管之前还有一个或多个fetchData还没有结束。如果我们只想得到最新请求的响应(比如总是显示最新版本的数据),我们可以使用takeLatest来辅助函数import{takeLatest}from'redux-saga'function*watchFetchData(){yield*takeLatest('FETCH_REQUESTED',fetchData)}与takeEvery不同,takeLatest任何时候只允许执行一个fetchDat一个任务,这个任务是最后一个开始的。如果之前已经有任务在执行,那么之前的任务会自动取消。2.EffectCreatorsredux-saga框架提供了很多创建效果的函数。简单介绍一下开发中最常用的take(pattern)put(action)call(fn,...args)fork(fn,...args)select(selector,...args)take(pattern)的take函数可以理解为倾听未来的行动。它创建一个命令对象并告诉中间件等待特定的操作。Generator会暂停,直到启动了匹配模式的动作,然后才继续执行后面的语句。也就是说,take是一个阻塞作用Usage:function*watchFetchData(){while(true){//监听一个类型为'FETCH_REQUESTED'的action的执行,直到Action被触发,下面的yieldfork(fetchData)语句yieldtake('FETCH_REQUESTED');产量叉(fetchData);}}put(action)put函数用于发送action的效果,可以简单理解为redux框架中的dispatch函数,当put一个action之后,会在reducer中计算并返回新的state.注意:put也是一个阻塞作用用法:exportfunction*toggleItemFlow(){letlist=[]//发送一个'UPDATE_DATA'类型的Action来更新Data,参数为`data:list`yieldput({type:actionTypes.UPDATE_DATA,data:list})}call(fn,...args)调用函数可以简单理解为调用其他函数函数,它命令中间件调用fn函数,args是函数的参数,注意注意:fn函数可以是Generator函数,也可以是返回Promise的普通函数。call函数也是阻塞效果用法:exportconstdelay=ms=>newPromise(resolve=>setTimeout(resolve,ms))exportfunction*removeItem(){try{//这里call函数调用了delay函数,而delay函数是一个返回promise的函数returnyieldcall(delay,500)}catch(err){yieldput({type:actionTypes.ERROR})}}fork(fn,...args)fork函数和call函数很相似,都是用来调用其他函数的,但是fork函数是一个非阻塞函数,也就是程序执行完后,yieldfork(fn,args)一行代码后,下一行代码语句将立即执行,无需等待fn函数返回结果,执行完以下语句用法:import{fork}from'redux-saga/effects'exportdefaultfunction*rootSaga(){//下面四个Generator函数会在不阻塞执行的情况下一次性执行指示中间件调用提供的selector获取Store上的状态数据,也可以简单理解为和redux框架中获取store上的状态数据一样的函数:store.getState()用法:export函数*toggleItemFlow(){//通过select效果获取全局state上`getTodoList`中的listlettempList=yieldselect(state=>state.getTodoList.list)}3.createSagaMiddleware()createSagaMiddleware函数用于创建Redux中间件并将Sagas与ReduxStore链接起来。sagas中的每个函数都必须返回一个Generator对象,中间件会迭代这个Generator并执行所有的YieldEffects(Effect可以看作是redux-saga的任务单元)。用法:import{createStore,applyMiddleware}from'redux'importcreateSagaMiddlewarefrom'redux-saga'importreducersfrom'./reducers'importrootSagafrom'./rootSaga'//创建saga中间件constsagaMiddleware=createSagaMiddleware()//创建storeconststore=createStore(reducers,将sagaMiddleware中间件传入applyMiddleware函数applyMiddleware(sagaMiddleware))//动态执行saga,注意:run函数只能在store创建后调用saga。middleware.run(rootSaga)exportdefaultstore4.middleware.run(sagas,...args)动态执行sagas,用于在applyMiddleware阶段之后执行sagassagas:Function:一个Generator函数args:Array:提供给saga的参数(Store的getState方法除外)注意:saga语句middleware.run(sagas)的动态执行必须在store创建后执行。在store之前执行,程序会报错拿CounterAppDemo看redux-sagaindex.jsimportReact的具体用法从'react';从'react-dom'导入ReactDOM;从'redux'导入{createStore,applyMiddleware}来自'./reducers'constsagaMiddleware=createSagaMiddleware()letmiddlewares=[]middlewares.push(sagaMiddleware)constcreateStoreWithMiddleware=applyMiddleware(...middlewares)(createStore)conststore=createStoreWithMiddleware(rootReducer)sagaMiddleware.run(rootSaga)constaction=type=>store.dispatch({type})functionrender(){ReactDOM.render(action('INCREMENT')}onDecrement={()=>action('DECREMENT')}onIncrementAsync={()=>action('INCREMENT_ASYNC')}/>,document.getElementById('root'))}render()store.subscribe(render)sagas.jsimport{put,call,take,fork}from'redux-saga/effects';import{takeEvery,takeLatest}来回m'redux-saga'exportconstdelay=ms=>newPromise(resolve=>setTimeout(resolve,ms));function*incrementAsync(){//执行前延迟1s+1操作yieldcall(delay,1000);yieldput({type:'INCREMENT'});}exportdefaultfunction*rootSaga(){//while(true){//yieldtake('INCREMENT_ASYNC');//yieldfork(incrementAsync);//}//下面等价于上面的yield*takeEvery("INCREMENT_ASYNC",incrementAsync)}reducer.jsexportdefaultfunctioncounter(state=0,action){switch(action.type){case'INCREMENT':returnstate+1case'DECREMENT':returnstate-1case'INCREMENT_ASYNC':returnstatedefault:returnstate}}从上面的代码结构可以看出redux-saga的使用比较简单,相比之前reduxframework对于CounterApp,多了一个sagas文件,reducers文件还是之前的使用方式。小结本文讲解redux-saga框架开发中最常用的常用API,还有很多不常用的API。请参考redux-saga官方文档:http://leonshi.com/redux-saga-in-chinese/docs/api/index.html如果同学看了这里的文章,对基本使用还是不熟悉redux-saga框架,概念比较模糊,建议看看作者提供的Demo例子。作者建议:同学们可以使用作者之前讲解过的reduX框架和redux-saga框架对比学习理解,让他们的区别更清楚,接触更多文章作者ReactNative开源项目OneM【500+星】地址(根据企业开发开发搭建框架的标准):https://github.com/guangqiang-liu/OneM:欢迎来到star作者简书主页:收录RN开发相关技术文章60余篇http://www.jianshu.com/u/023338566ca5欢迎小伙伴们:多多关注,多点赞作者ReactNativeQQ技术交流群:620792950欢迎小伙伴们进群交流学习提问,互相学习。交流群也会定期为大家更新最新的RN学习资料,感谢大家的支持!小伙伴们扫描下方二维码加入RN技术交流QQ群