中文文档地址
特点:
- 纯净
- 强大
- 灵活
在saga任务中,如果yield了一个普通数据,saga不做任何处理,仅仅将数据传递给yield表达式(把得到的数据放到next参数中),因此,在saga中,yield一个普通数据没有什么意义
saga需要你在yield后面放上一些合适的saga指令(saga effects),如果放的是指令,saga中间件会根据指令来做出不同的处理,以控制整个任务流程
import { createStore, applyMiddleware } from 'redux'
import * as usersAction from './action/student/usersAction'
import * as numberAction from './action/counter/number-action'
import { bindActionCreators, combineReducers } from '../redux/index'
import { v4 as uuid4 } from 'uuid'
import loginUser from './reducer/loginUser'
import numberReducer from './reducer/numberReducer'
import usersReducer from './reducer/usersReducer'
import logger from 'redux-logger';
import thunk from 'redux-thunk'
import createSagaMiddleware from 'redux-saga'
import { all } from 'redux-saga/effects'
import counterTask from '../saga/counterTask'
const reducers = combineReducers({
loginUser: loginUser,
numberReducer: numberReducer,
usersReducer: usersReducer
})
export function* sagaTask() {
yield all([counterTask()]);
console.log("任务完成");
}
const sagaMiddleware = createSagaMiddleware();
const store = createStore(reducers, applyMiddleware(sagaMiddleware, logger));
sagaMiddleware.run(sagaTask);
const bindAction = bindActionCreators(numberAction, store.dispatch)
bindAction.getIncreaseAction();
saga指令本质上就是一个函数,该函数调用后,会返回一个指令对象,saga会接收到该指令对象进行各种处理,yield会返回一个完整的action
指令 | 内容 |
---|
take | 【会造成阻塞】监听某个action,如果action发生了改变,则会进行下一步处理,take指令仅监听一次,yield得到的是完整的action对象。pattern为空 或者 * ,将会匹配所有发起的action。 pattern是一个函数,action 会在 pattern(action) 返回为 true 时被匹配 |
all | 【阻塞】该函数传入一个数组,数组中放入生成器,saga会等待所有生成器全部完成后才会进行下一步处理。 |
takeEvery | 不断的监听某个action,当某个action到达之后,运行一个函数,takeEvery永远不会结束当前的生成器。 |
delay | 【阻塞】阻塞指定的毫秒数。 |
import { takeEvery, take, delay } from 'redux-saga/effects'
import * as actionType from '../store/action/action-type'
function* increase() {
yield delay(2000)
console.log("increase运行")
}
function* decrease() {
yield delay(2000)
console.log("decrease运行")
}
export default function* counterTask() {
console.log("conterTask运行");
let data = yield takeEvery(actionType.INCREASE, increase);
data = yield takeEvery(actionType.DECREASE, decrease);
console.log(data);
}
运行结果:
action increase @ 10:59:12.572
prev state {loginUser: null, numberReducer: 10, usersReducer: Array(0)}
action {type: "increase"}
next state {loginUser: null, numberReducer: 11, usersReducer: Array(0)}
action decrease @ 10:59:12.575
prev state {loginUser: null, numberReducer: 11, usersReducer: Array(0)}
action {type: "decrease"}
next state {loginUser: null, numberReducer: 10, usersReducer: Array(0)}
increase运行(两秒后运行)
decrease运行(两秒后运行)
指令 | 内容 |
---|
put | 用于重新触发action,相当于dispatch触发action。 |
import { getIncreaseAction } from '../store/action/counter/number-action'
export default function* counterTask() {
console.log("conterTask运行");
const result = yield put(getIncreaseAction());
console.log(result)
}
运行结果:
conterTask运行
action increase @ 11:16:50.651
prev state {loginUser: null, numberReducer: 10, usersReducer: Array(0)}
action {type: "increase", @@redux-saga/SAGA_ACTION: true}
next state {loginUser: null, numberReducer: 11, usersReducer: Array(0)}
{type: "increase", @@redux-saga/SAGA_ACTION: true}type: "increase"@@redux-saga/SAGA_ACTION: true__proto__: Object
任务完成
指令 | 内容 |
---|
call | 【可能阻塞】 用于副作用函数调用(通常是异步)。 |
apply | 【可能阻塞】apply的作用和call是一样,只有传入的参数不一样,第一个参数传入的是this的指向,第二个参数传入调用的函数,第三个是传入函数的参数,apply为一个数组,call为字符串。 |
import { takeEvery, take, delay, put, call, apply } from 'redux-saga/effects'
import * as actionType from '../store/action/action-type'
function* increase() {
yield delay(2000)
console.log("increase运行")
}
function* decrease() {
yield delay(2000)
console.log("decrease运行")
}
function asyncGetStudent(name, age) {
setTimeout(() => {
console.log("call 调用副作用函数");
console.log(name, age)
return { name: name, age: age }
}, 3000)
}
export default function* counterTask() {
console.log("conterTask运行");
const result = yield call(asyncGetStudent, "qian", 18);
yield apply(null, asyncGetStudent, ["ren", 18])
console.log(result)
}
运行结果:
call 调用副作用函数
qian 18
call 调用副作用函数
ren 18
指令 | 内容 |
---|
select | 查询整个仓库当前的状态。返回值为当前仓库的状态。 |
import { takeEvery, take, delay, put, call, apply, select } from 'redux-saga/effects'
import * as actionType from '../store/action/action-type'
export default function* counterTask() {
console.log("conterTask运行");
const state = yield select();
console.log(state)
}
运行结果:
conterTask运行
{loginUser: null, numberReducer: 10, usersReducer: Array(0)}
指令 | 内容 |
---|
cps | 【可能阻塞】用于调用那些传统的回调方式的异步函数 |
import { takeEvery, take, delay, put, call, apply, cps } from 'redux-saga/effects'
import * as actionType from '../store/action/action-type'
function asyncGetStudent(callback) {
setTimeout(() => {
if(Math.random() > 0.5){
callback(null, {
cont:100,
datas:[
{name:"qian", age:20 }
]
})
}
else{
callback(new Error("callback 出错啦"), null)
}
}, 3000)
}
export default function* counterTask() {
console.log("conterTask运行");
const result = yield cps(asyncGetStudent);
console.log(result)
}
运行结果:3秒后
{cont: 100, datas: Array(1)}cont: 100datas: Array(1)0: {name: "qian", age: 20}length: 1__proto__: Array(0)__proto__: Object
指令 | 内容 |
---|
fork | 用于开启一个新的任务,该任务不会阻塞,该函数需要传递一个生成器函数,相当于新开了一个任务线。fork返回了一个对象,类型为Task |
cancel | 用于取消一个或者多个任务, 实际上,用的是generator.return来做的,cancel可以不传参数,如果不穿参数,则取消自身的任务线。 |
takeLastest | 功能和takeEvery一致,但是,会自动取消之前开启的任务 |
import { takeEvery, delay, put, fork, take, cancel } from 'redux-saga/effects'
import { getIncreaseAction } from '../store/action/counter/number-action'
import * as actionType from '../store/action/action-type'
let task;
function* asyncAutoIncrease() {
while (true) {
yield take(actionType.AUTOINCREASE)
if (task) {
yield cancel(task);
}
task = yield fork(function* () {
while (true) {
yield delay(2000);
yield put(getIncreaseAction());
}
})
}
}
function* asyncStopAutoIncrease() {
if (task) {
yield cancel(task);
}
}
export default function* counterTask() {
console.log("conterTask运行");
yield fork(asyncAutoIncrease);
yield takeEvery(actionType.STOPAUTOINCREASE, asyncStopAutoIncrease);
console.log("正在监听 asyncAutoIncrease")
}
import { cancel, delay, fork, put, take } from 'redux-saga/effects'
import { getIncreaseAction } from '../store/action/counter/number-action'
import * as actionType from '../store/action/action-type'
let task;
function* autoTask() {
while (true) {
yield take(actionType.AUTOINCREASE)
task = yield fork(function* () {
while (true) {
yield delay(2000);
yield put(getIncreaseAction());
}
})
yield take(actionType.STOPAUTOINCREASE);
yield cancel(task);
}
}
export default function* counterTask() {
console.log("conterTask运行");
yield fork(autoTask)
console.log("正在监听 asyncAutoIncrease")
}
指令 | 内容 |
---|
cancelled | 判断当前任务先是否被取消 |
import { cancel, cancelled, delay, fork, put, take } from 'redux-saga/effects'
import { getIncreaseAction } from '../store/action/counter/number-action'
import * as actionType from '../store/action/action-type'
let task;
function* autoTask() {
while (true) {
yield take(actionType.AUTOINCREASE)
task = yield fork(function* () {
try {
while (true) {
yield delay(2000);
yield put(getIncreaseAction());
}
} finally {
if(yield cancelled()){
console.log("任务被取消了")
}
}
})
yield take(actionType.STOPAUTOINCREASE);
yield cancel(task);
}
}
export default function* counterTask() {
console.log("conterTask运行");
yield fork(autoTask)
console.log("正在监听 asyncAutoIncrease")
}
指令 | 内容 |
---|
race | 【阻塞】竞赛,可以传递多个指令,当其中任何一个指令结束后,会直接结束,于Promise.race类似,返回的结果是最先完成的结果,然后会自动取消其他的任务 |
import { call, fork, race } from 'redux-saga/effects'
import { getIncreaseAction, getDecreaseAction } from '../store/action/counter/number-action'
import * as actionType from '../store/action/action-type'
let task;
function asyncAction() {
let duration = Math.floor(Math.random() * 4000 + 1000);
console.log(duration);
return new Promise(resolve => {
setTimeout(function () {
if (Math.random() > 0.5){
resolve(getIncreaseAction())
}
else{
resolve(getDecreaseAction())
}
}, duration)
})
}
export default function* counterTask() {
const result = yield race({
action1: yield call(asyncAction),
action2: yield call(asyncAction)
})
console.log(result);
}