文章目录
资料
文档:
参考文章:
redux-saga简介
使用 dispatch 往 store 发送 action 的这个过程是可以被拦截的, 自然而然地就可以在这里增加各种中间件Middleware。redux-saga是redux的中间件,主要负责从action派发到更新store中间具有副作用行为的处理。
sagas.js文件
import {
all, put, takeEvery } from 'redux-saga/effects'
function* increment() {
// 相当于:dispatch({ type: 'increment' })
yield put({
type: 'increment' })
}
function* watchIncrement() {
// 监听类型为increment_saga的action,监听到启动increment
yield takeEvery('increment_saga', increment)
}
function* rootSaga() {
// 启动watchIncrement
yield all([watchIncrement()])
}
export default rootSaga
这些generator函数我们叫它saga。saga中yield 后面的内容我们称呼它为Effect(redux-saga的任务单元),在Effects中我们可以进行启动其它saga,也可以处理一些副作用操作。Effects是一些简单对象,如下put({ type: ‘increment’ }),我们使用redux-saga提供的put方法创建一个Effect对象。如果直接打印Effect:
console.log(put({
type: 'increment' }));
在 redux-saga 的世界里,Saga 都用 Generator 函数实现。我们从 Generator 里 yield 纯 JavaScript 对象以表达 Saga 逻辑。 我们称呼那些对象为 Effect。Effect 是一个简单的对象,这个对象包含了一些给 middleware 解释执行的信息。 你可以把 Effect 看作是发送给 middleware 的指令以执行某些操作(调用某些异步函数,发起一个 action 到 store,等等)。
常用API
takeLatest
takeLatest是非阻塞的。
顾名思义takeEvery监听每一次对应action的派发,而takeLatest监听最后一次action的派发,并自动取消之前已经在启动且任在执行的任务。 这个和我们的防抖很类似。
takeLatest(pattern, saga, …args): 监听类型为pattern的action的派发,当监听到该类型的action,将执行第二个参数saga,且如果存在上一次已经启动且仍在运行的该saga,takeLatest将取消上一次该saga的运行。
- pattern:takeLatest将监听类型为pattern的action的派发。takeLatest第一个参数是*,即不再匹配某一个具体的action,而是匹配所有的action
- saga:监听到对应action,启动对应saga。
- args:传递给saga函数的参数。如果takeLatest没有传入args,那么saga函数的参数只有一个,即类型为pattern的action。如果takeLatest传入了其它args参数,那么saga函数的参数将像这样(args,action)。
takeLatest会创建一个一直执行的任务,该任务的功能是监听类型为xxx的action执行对应的saga。且takeLatest是非阻塞的,即中间件接收到takeLatest创建的Effect之后就去创建一个一直执行的任务,同时继续执行yield takeLatest(‘xxx’, login)后面的代码。takeEvery同理。
function* increment() {
yield put({
type: 'increment' })
}
function* watchIncrement() {
yield takeLatest('increment_saga', increment)
}
takeEvery
takeEvery是非阻塞的。
takeEvery(pattern, saga, ...args)
: 监听类型为pattern的action的派发,当监听到该类型的action,将执行第二个参数saga,且args将作为参数传递给saga函数,与takeLatest唯一不同即 不会取消之前监听到类型pattern的action且正在执行的saga任务。
function* increment() {
yield put({
type: 'increment' })
}
function* watchIncrement() {
// 监听类型为increment_saga的action,监听到启动increment
yield takeEvery('increment_saga', increment)
}
take
take是阻塞的。
take接受的参数type即用来匹配action的类型,take作用是创建一个Effect,命令中间件等待指定的action到来(下方代码是等待类型为loginOut的action到来),只监听一次。在该action到来之前,将暂停当前Generator。take()的返回值是当前aciton。
function* loginOut() {
yield put({
type: 'loginSuccess', loginInfo: {
success: false, name: '', password: '' } })
}
// 监听登录登出saga
function* watchLogin() {
yield takeLatest('login', login)
// 1,使用take等待类型loginOut的action的到来,take将阻塞当前Generator
const action = yield take('loginOut')
// 2,take监听到类型loginOut的action,执行yield call(loginOut),即继续登出操作
yield call(loginOut)
}
当yield take(‘loginOut’)等待的类型为loginOut的action到来时,Generator开始继续执行后面的代码,即 yield call(loginOut),call将创建一个Effect,命令中间件执行loginOut方法,完成后续的登出操作,因为call方法是阻塞的,所以当前Generator会等待loginOut的完成。当loginOut完成之后,该Generator函数将执行完毕。
Generator函数(即watchLogin)将执行完毕退出后,此时只有yield takeLatest(‘login’, login)创建的监听login的任务仍然在后台运行。所以往后再有退出的loginOut类型的action派发过来的,并没有任何任务对其保持监听,所以将中间件将忽略掉后续过来的loginOut类型的action。
delay
delay(timeout,[val])
: 产生一个阻塞的Effect(Effect=>任务单元),阻塞timeout毫秒,并返回val(val非必传)。大白话就是yield delay(1000,‘Love U’)将阻塞当前代码执行1000ms,并且返回’Love U’。
import {
put, delay } from 'redux-saga/effects'
function* increment() {
yield put({
type: