我正在试图找出如何在redux-saga中合并取消相同操作类型的多个任务。基本上,当我的组件在componentWillUnmount()
时,我想取消它可能已经开始的所有任务。
如果我有以下操作(这与我在代码中实际拥有的内容大大简化,但我正在尝试将其简化为必需品):
// Action
export const loadMyData = params => {
let url = /* Create URL based on params */
return {
type: FETCH_DATA,
url,
key: /* a unique key so we can retrieve it in the state later */
}
}
以下传奇:
// Saga
export function* fetchData(action) {
try {
// 'callApi()' currently uses axios
let response = yield call(callApi, action.url);
yield put({
type: FETCH_SUCCESS,
key: action.key,
payload: response.data
});
} catch(error) {
yield put({
type: FETCH_FAILURE,
error
});
}
}
export function* watchFetchData() {
while (true) {
let action = yield take(FETCH_DATA);
let task = yield fork(fetchApi, action);
}
}
如上所述,组件可多次调用loadMyData()
。此外,可能还有其他组件也称为loadMyData()
。所以我试图找到一种方法来取消componentWillUnmount()
状态的组件中的任务,但保留其他任何正在运行的任务。
在Redux Saga Cancellation documentation中,他们的示例适用于需要在之后执行取消操作的单个任务。我无法弄清楚如何将其扩展到我的用例。
答案 0 :(得分:1)
我想到的是以下内容:
在componentWillMount
中,您通过调度操作并将任务存储在减速器中来注册组件,如下所示:
registerWatchFetchData = (componentKey) => {
return {
type: "REGISTER_WATCH_FETCH_DATA",
payload: { componentKey }
}
}
减速器:
// ...
case "REGISTER_WATCH_FETCH_DATA":
return {...state, tasks: {...state.tasks, [action.payload.componentKey]: []}}
然后在function* watchFetchData()
内部,您将新任务存储在reducer中,用于键入您在payload
中提供的componentKey的相应组件:
export function* watchFetchData() {
while (true) {
let action = yield take(FETCH_DATA);
let task = yield fork(fetchApi, action);
yield put({ type: "STORE_TASK", payload: { componentKey: action.payload.componentKey, task } })
}
}
然后添加到reducer
// ...
case "STORE_TASK":
return {...state, tasks: {...state.tasks, [action.payload.componentKey]: [...state.tasks[action.payload.componentKey], action.payload.task]}}
在componentWillUnmount
中你发出另一个动作来告诉一个saga拉出componentKey的所有任务,迭代它们并取消它们就像这样:
function* watchUnregisterComponent(){
while(true){
const action = yield take("UNREGISTER_WATCH_FETCH_DATA")
const componentTasks = yield select(state => state.myReducer.tasks[action.payload.componentKey])
componentTasks.forEach((t) => {
yield cancel(t)
})
// dispatch another action to delete them from the reducer
}
}