Sagas

Sagas

我们可以理解为Sage是一个可以用来处理复杂的异步逻辑的模块,并且由reduxaction触发。副作用就是在action触发reduser之后执行的一些动作,这些动作包括但不限于,连接网络,io读写,触发其他action。并且,因为Sage的副作用是通过reduxaction触发的,每一个actionsage都会像reduser一样接收到。并且通过触发不同的action,我们可以控制这些副作用的状态,例如,启动,停止,取消。

redux-sagas 示意图

Redux Sagas 示意图

基础使用

在定义生成store的地方,引入并加入redux-sage中间件。

// npm install --save redux-saga
import { createStore, applyMiddleware } from "redux";
import createSagaMiddleware from "redux-saga";

import reducer from "./reducers";
import mySaga from "./sagas";

// create the saga middleware
const sagaMiddleware = createSagaMiddleware();
// mount it on the Store
const store = createStore(reducer, applyMiddleware(sagaMiddleware));

// then run the saga
sagaMiddleware.run(mySaga);

副作用

副作用,顾名思义,在主要作用(action触发reducer)之外,用来处理其他业务逻辑。redux-saga提供了几种产生副作用的方式,主要用到了有两种takeEverytakeLates

  • takeEvery类似于redux-thunk的作用,会在接到相应的action之后不断产生新的副作用。比如,做一个计数器按钮,用户需要不断的点击按钮,对后台数据更新,这里可以使用takeEvery来触发。

  • takeLatest在相同的action被触发多次的时候,之前的副作用如果没有执行完,会被取消掉,只有最后一次action触发的副作用可以执行完。比如,我们需要一个刷新按钮,让用户可以手动的从后台刷新数据,当用户不停单机刷新的时候,应该最新一次的请求数据被刷新在页面上,这里可以使用takeLatest

在下面的事例中,当我们点击Fetch按钮时,其会触发某个 FETCH_REQUESTED 动作,然后Sagas中的监听函数会自动去监听该动作并且触发数据加载:

import { call, put } from "redux-saga/effects";
import { takeEvery } from "redux-saga";

export function* fetchData(action) {
  try {
    const data = yield call(Api.fetchUser, action.payload.url);
    yield put({ type: "FETCH_SUCCEEDED", data });
  } catch (error) {
    yield put({ type: "FETCH_FAILED", error });
  }
}

function* watchFetchData() {
  yield* takeEvery("FETCH_REQUESTED", fetchData);
}

注意,takeEvery第一个参数可以是数组或者方法。也可以有第三个参数用来传递变量给方法。takeEvery会允许同时创建多个fetchData实例,这也就意味着可能某个时刻,某个fetchData在被执行的时候,它还有多个fetchData的动作尚未完成。如果我们只希望展示最新的数据请求的结果,则应该使用taskLatest:

import { takeLatest } from "redux-saga/effects";

function* watchFetchData() {
  yield takeLatest("FETCH_REQUESTED", fetchData);
}

takeLatest同一时刻仅允许单个fetchData的任务运行,如果某个先前的任务尚未执行完毕,则其会被自动地终止。我们也可以同时创建多个监听函数:

import { takeEvery } from 'redux-saga/effects'

// FETCH_USERS
function* fetchUsers(action) { ... }

// CREATE_USER
function* createUser(action) { ... }

// use them in parallel
export default function* rootSaga() {
  yield takeEvery('FETCH_USERS', fetchUsers)
  yield takeEvery('CREATE_USER', createUser)
}

Links

上一页
下一页