什么是redux-saga?
中间件的执行流程 :
action -> Middlewares -> reducer
- redux-saga 是一个用于管理应用程序副作用的 library,它的目的是让副作用管理更加的简单,执行更高效(作用)
- redux-saga 就是一个 redux 的中间件,可以通过正常的
redux action从主应用程序启动,暂停和取消,它可以访问完整的redux state,也能够dispatch redux action(使用) - redux-saga 使用了ES6的 Generator 功能 ,让异步流程更加易于读取,写入,测试,通过这种方式,让异步看起来更加像标准同步的js代码(本质)
为什么使用redux-saga?
在处理这些副作用时,我们需要一种方式来控制它们的执行顺序,处理可能出现的错误,以及在需要的时候取消它们。这就是 redux-saga 和其他副作用管理库的用武之地
API介绍
注册使用
createSagaMiddleware(options): 创建一个 Redux middleware ,并将Sagas连接到 Redux Store,通过 createStore 第三个参数传入- options: 传递给 middleware 的选项列表,默认可以不用传递
middleware.run(saga,...args): 动态地运行saga,只能用于在 applyMiddleware 阶段之后执行Saga
监听action
takeEvery(pattern,saga,...args): 监听每一次Action,匹配到Action便会执行一次(所有)- pattern: 与 action 参数的 type 同名
- saga: 回调函数
takeLatest(pattern,saga,...args): 监听匹配的Action,每次触发,会取消掉上一次正在执行的异步任务,请求数据一般用这个(最后一个)throttle(ms,pattern,saga,...args): 匹配到一个对应的action后,会执行一个异步任务,但是同时还会接收一次对应action的异步任务,放在底层的buffer中,那么在第一个参数 ms 毫秒内将不会执行异步任务(第一个和第二个)take(pattern): 阻塞的方法,用来匹配发出的action- take 返回一个对象,为 action 的参数
- take 返回一个对象,为 action 的参数
其他方法
select(): 获取 reducer 的返回结果,如果调用的参数为则全都返回- 返回参数为经过 reducer 后的 return 值,虽然只触发了一个 reducer,但是会返回两个
- 返回参数为经过 reducer 后的 return 值,虽然只触发了一个 reducer,但是会返回两个
call(fn,...args): 创建一个阻塞任务的 Effect 。在Generator函数中使用yield call时,它会暂停Saga的执行,等待被调用函数执行完成,并将结果返回- fn 可以是一个 异步函数、生成器函数
fork(fn,...args): fork是一个用于创建非阻塞任务的 Effect。与call不同,fork不会阻塞Generator函数的执行,而是会立即返回一个任务描述符,允许调用者继续执行后续的操作cancel(task):cancel方法用于取消一个正在运行的任务。这是通过取消 generator 函数中正在运行的 Effect 来实现的。取消任务可以通过调用yield cancel(task)来完成,其中task是通过fork或spawn创建的任务cancelled():cancelled是一个用于检查任务是否被取消的函数。你可以在 generator 函数中使用yield cancelled()来获取一个布尔值,指示当前任务是否被取消put(action): 用来命令 middleware 向 Store 发起一个 action。这个 Effect 是非阻塞型的race(): 用于创建一个竞速条件,它允许在多个 Effect 之间竞争,然后在其中一个 Effect 完成时终止其他 Effectall([]...effects): 合并saga监听函数(模块化)
为什么使用 while(ture){} 配合 take()
为了表示一个逻辑执行流程,利用 take() 的阻塞属性
登录注册为例: 在触发登录之后,执行登录逻辑,比如存用户信息,更新登录状态;之后才能触发退出登录的逻辑,所以退出登录的监听在登录之后
function* authorize(info) {
try {
const token = yield call(userLogin, info)
yield put({ type: LOGIN_SUCCESS, token })
// 保存 token
yield call(saveToken, { token })
return token
} catch (error) {
yield put({ type: LOGIN_FAIL});
} finally {
if (yield cancelled()) {
// ... 修改登录状态
}
}
}
function* userSaga() {
while (true) {
const { payLoad } = yield take(LOGIN)
const task = yield fork(authorize, payLoad);
const action = yield take([LOGOUT, LOGIN_FAIL]);
if (action.type === LOGOUT) {
yield cancel(task);
}
// 清除token
yield call(clearToken())
}
}
export default userSaga;
在多个 Effects 之间启动 race()
功能: 允许你同时启动多个任务,然后在其中一个任务完成时终止其他任务
应用场景: 可以用来控制一个请求的超时时间
function* fetchData() {
try {
const result = yield race({
data: call(api.getData),
timeout: call(delay, 5000) // 设置一个5秒的超时
});
if (result.data) {
yield put({ type: 'FETCH_SUCCESS', payload: result.data });
} else {
yield put({ type: 'FETCH_TIMEOUT' });
}
} catch (error) {
yield put({ type: 'FETCH_ERROR', error });
}
}
组合 saga
- 使用
call():同时执行多个任务
const [users, repos] = yield [
call(fetch, '/users'),
call(fetch, '/repos')
]
- 使用
race():在多个 Effects 之间启动 - 使用
yield*:内置的 yield* 操作符来组合多个 Sagas,排列宏观任务使用示例
使用流程
- 注册使用
import reducer from './reducers';
import states from './states';
import actions from './actions';
import { applyMiddleware, legacy_createStore as createStore } from "redux";
import watchSaga from './sagas';
import createSagaMiddleware from 'redux-saga';
const sagaMiddleware = createSagaMiddleware();
// 用reducer实例化store
store = createStore(reducer,{},applyMiddleware(sagaMiddleware));
sagaMiddleware.run(watchSaga);
export default store;
- 编写 saga 文件,如果需要模块化则创建多个 saga 文件,使用
all()合并再导出