React-Saga

redux-saga 是一个用于管理应用程序 Side Effect(副作用,例如异步获取数据,访问浏览器缓存等)的 library,它的目标是让副作用管理更容易,执行更高效,测试更简单,在处理故障时更容易。

可以想像为,一个 saga 就像是应用程序中一个单独的线程,它独自负责处理副作用。 redux-saga 是一个 redux 中间件,意味着这个线程可以通过正常的 redux action 从主应用程序启动,暂停和取消,它能访问完整的 redux state,也可以 dispatch redux action。

如果你的Redux需要异步管理,请放心的使用saga来进行管理,如果使用同步可以,那么无需使用saga

saga采用ES6的Generator生成器函数,来实现异步的管理。最常见的就是链式调用,在ES7新出的版本中,async await关键字能更方便的实现链式调用,而且写代码的感觉就像是同步。下面从生成器函数开始;

一、生成器函数Generators

生成器函数是一种特殊类型的函数,与普通函数的不同之处在于: 它可以通过yield关键字来暂停执行并返回一个值,然后再继续执行。
定义方式:

function *gen(){
	yield 1
	yield 2
	yield 3
}
const myGen = gen()]
console.log(myGen.next()) // {value: 1,done: false}
console.log(myGen.next()) // {value: 2,done: false}
console.log(myGen.next()) // {value: 3,done: false}
console.log(myGen.next()) // {value: undefined,done: true}

yield表示在此处停止,等待其后的语句执行完毕返回结果,当调用next时继续往下执行。
需要注意的是:生成器函数不会立即执行,而是在迭代器首次调用next()方法时会执行

Saga

saga是用于处理Redux的异步编程的,首先先了解一下redux 的基本工作过程:

  • 创建store: 使用Redux中的createStore()创建一个Redux store,传入一个reducer函数,reducer是一个纯函数(类似于数组的slice方法,不改变原数组,纯函数是指不改变输入的值的函数),reducer用于来根据当前状态和操作类型来更改状态。
  • 分发action: 使用dispatch函数将一个action分发到store中,注意action对象必须是一个包含有type属性和其他的可能数据的对象。
  • Reducer处理action: 当一个action被分发到store中时,reducer函数会接收到当前状态和action,然后根据action的type值更新状态。
  • 更新store中的状态:reducer函数会返回新的状态并替换当前的状态,并保存在store中。
  • 订阅state的变化: 在需要访问store的组件中进行订阅,使用store.subscribe()来监听store的变化,每当状态发生变化时,订阅者都会进行调用重新执行。
    Redux在处理异步时,需要借助ReduxThunk或者Redux Promise来进行操作,同样也可以借助saga来进行操作。
    Saga更改的是上述步骤的第而步和第三步: saga是通过先创建一个saga任务,监听actions,当监听到action时立即同步执行action对应的异步请求,当请求返回数据后再使用内部函数put分发一个新的action,使用reduer进行更新状态

Saga的使用

  • 安装: npm i redux-saga
  • 使用:
    1.创建saga中间件: 使用createSagaMiddleware()函数创建一个saga中间件
    2.定义saga任务: 使用generator函数定义saga任务,该函数通过函数和yield关键字来描述副作用
    3.监听action: 通过在saga中使用takeEvery(),takeLastest()等函数监听指定的action’
    4.触发action:在组件中触发已监听的action匹配的动作时,redux-saga会自动调用相应的saga任务
    5.执行saga任务: saga中间件将启动saga任务,并以非阻塞式的方式执行generators函数
    6.处理副作用: 在saga 函数中可以使用一系列的effect函数处理不同类型的操作,例如:使用call函数调用一个需要异步操作的函数,使用put分发一个新的action
    7.监控任务状态: 根据需要,使用take,put,takeEvery,all等effect函数执行saga任务的顺序
    8.终止saga任务: 可以使用cancel或相关的effect函数来发送一个取消指令‘
    9.运行saga中间件: 将saga中间件作为Redux store的参数之一,通过applyMiddleware()函数将其应用到Redux store中。
    总的来说:Redux-saga的工作原理是通过监听和相应不同的action触发generators函数中描述的副作用。中间件会以非阻塞式的方式来执行这些副作用,并且提供了内置函数来处理副作用。

使用示例

store.js

import { createStore,applyMiddleware } from 'redux'
import reducer from './reducer'
import createSagaMiddleWare from 'redux-saga'
import WatchSage from './saga'

//利用redux-saga生成一个对象,再将对象传入applyMiddleWare
const SagaMiddleWare = createSagaMiddleWare()
const store  =  createStore(reducer,
    applyMiddleware(SagaMiddleWare))

SagaMiddleWare.run(WatchSage) // 运行saga任务,需要自己手写
export default store

saga.js

import { all } from 'redux-saga/effects'
import watchSaga1 from "./saga/saga1";
import watchSaga2 from "./saga/saga2";
function *WtachSaga(){
    // all的作用是将所有的saga函数进行聚合,统一地进行监听
    yield all([watchSaga1(),watchSaga2()])
}
export default WtachSaga

saga1.js

import { take, fork,call,put,takeEvery} from 'redux-saga/effects'
// function *watchSaga1(){
//     while (true){
//         //take函数: 监听组件发来的action
//         //fork函数: 同步执行异步处理函数
//         yield take("get-list1")
//         yield fork(getListArr1)
//     }
// }
//第二中写法
function *watchSaga1(){
    //takeEvery接受两个参数: 第一个是组件传来的action  第二个参数是向reducer传递的action
    yield takeEvery('get-list1',getListArr1)
}
//getListArr专门做异步处理
function *getListArr1(){
//     发异步请求 call函数发异步请求,阻塞式的调用
//     put函数发出新的action,非阻塞式的执行
    let res = yield call(getListAction1) //call的参数要求是一个返回值是promise对象的函数
    yield put({
        type: 'change-list1',
        payload: res
    })

}

function getListAction1(){
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve([1,2,3,4,5])
        },2000)
    })
}
export default watchSaga1
export  {getListArr1}

reducer中的处理:

function reducer(prevState = {
    list: [],
    list2:[]
},action={}){
    const newState = {...prevState}
    switch (action.type){
        case 'change-list1':
            console.log(action)
            newState.list = action.payload
            return newState
        case 'change-list2':
            newState.list2 = action.payload
            return newState
        default:
            return newState
    }
}
export default reducer

最后在app.js进行触发:

import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

另外,采用takeEvery函数也可以实现链式调用和传参

import { all,takeEvery } from 'redux-saga/effects'
import watchSaga1 from "./saga/saga1";
import watchSaga2 from "./saga/saga2";
import {getListArr1} from "./saga/saga1";
import {getListArr2} from './saga/saga2'
function *WtachSaga(){
    // all的作用是将所有的saga函数进行聚合,统一地进行监听
    yield yield takeEvery('get-list1',getListArr1)
    yield yield takeEvery('get-list2',getListArr2)
}
export default WtachSaga

大概就是这样一个过程,只是多加了一步用生成器函数处理异步请求再进行分发触发reducer更新状态

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值