官方文档:https://redux-saga.js.org/
saga
redux-saga
是 redux
的一个异步处理工具
相同的工具还有 redux-thunk
相比之下我觉得 redux-thunk
的上手难度比较低,redux-saga
本身的 generator
特性使异步的处理更加地优雅
组织方式
在一个 saga
内部
saga
宏观布局
宏观布局
某saga (事件)
// worker saga
function* loginHandle(action) {
try {
// 两个顺序异步请求
const res1 = yield call(LoginService.login, action.payload);
const res2 = yield call(LoginService.getMoreUserInfo, res1);
// 状态更新
yield put({type: LOGIN_SUCCESS, payload: res2});
} catch (err) {
yield put({type: LOGIN_FAILURE, payload: err});
}
}
// watcher saga
function* loginSaga() {
yield takeEvery(LOGIN_SAGA, loginHandle);
}
export default loginSaga;
事件总线
import {all} from "redux-saga/effects";
import loginSaga from "./loginSaga";
export default function* rootSaga() {
yield all([loginSaga()]);
}
Store
import {loginReducer} from "./loginReducer";
import {createStore, combineReducers, applyMiddleware} from "redux";
import createSagaMiddleware from "redux-saga";
import rootSaga from "../action/rootSaga";
// step1. 创建saga中间件
const sagaMiddleware = createSagaMiddleware();
const store = createStore(
combineReducers({user: loginReducer}),
// step2. 在创建的商店中应用
applyMiddleware(sagaMiddleware)
);
// step3. 开始监听事件总线
sagaMiddleware.run(rootSaga);
export default store;
微观布局
以下 API 均从 redux-saga/effects
导入
// eg.
import {call, fork, put, take} from "redux-saga/effects";
监听
- takeEvery(类型,回调)
- takeLatest(类型,回调)
最后一次执行会终止上一次执行,和防抖类似 - take(类型,回调)
只执行一次
eg.
// watcher saga
function* loginSaga() {
yield takeEvery(LOGIN_SAGA, loginHandle);
}
export default loginSaga;
// 1.此处的 LOGIN_SAGA 就是 reducer 的 type
// 2.对于需要用 saga 处理的 reducer,
// 监听的地方和传统的 reducer不同,
// saga 监听的对象单独拎出来放在以上API的第一个参数
用其他 API 实现 takeEvery
const takeEvery = (pattern, saga, ...args) =>
call(function*() {
while (true) {
const action = yield take(pattern);
yield fork(saga, ...args.concat(action));
}
});
执行
- call
yield call([obj, obj.method], arg1, arg2, …)
const products = yield call(Api.fetch, '/products')
- fork
用法和call
类似,只是fork
是非阻塞,而call
是阻塞的
意思是如果某次call
需要用到上一次的值,那就不能用fork
了 - apply
yield apply(obj, obj.method, [arg1, arg2, …]) - cps
用于处理组件回调 (这个地方官方没有给出实际例子,笔者目前也没有遇到过这样的场景,暂时举不出例子)
eg.
// worker saga
function* loginHandle(action) {
try {
// 两个顺序异步请求
const res1 = yield call(LoginService.login, action.payload);
const res2 = yield call(LoginService.getMoreUserInfo, res1);
// 状态更新
yield put({type: LOGIN_SUCCESS, payload: res2});
} catch (err) {
yield put({type: LOGIN_FAILURE, payload: err});
}
}
派发
一、worker saga
的参数
function* fetchProducts (dispatch) {
const products = yield call(Api.fetch, '/products');
dispatch({type: 'XXX', products});
}
注意:官方并不推荐在生成器内部调用函数这种用法
二、put
function* fetchProducts () {
const products = yield call(Api.fetch, '/products');
yield put({type: 'XXX', products});
}
感谢你能看到这里~