如何单独停止指定Saga实例并监听全部Saga完成状态?
解决方案
要实现单独停止指定pollSaga实例并监听所有实例完成的需求,可以从给停止动作添加标识和跟踪任务状态两方面入手,具体实现如下:
1. 让停止动作绑定特定ID
修改STOP_ACTION为带payload的结构,携带目标实例的ID,这样每个pollSaga只会响应对应自己ID的停止信号:
function* pollSaga(id) { yield race([ call(workSaga, id), // 只监听携带当前id的STOP_ACTION take(action => action.type === 'STOP_ACTION' && action.payload.id === id) ]) }
当需要停止某个特定实例时,分发对应ID的动作即可:
// 停止id为"xxx"的pollSaga实例 dispatch({ type: 'STOP_ACTION', payload: { id: 'xxx' } })
2. 监听所有pollSaga完成状态
mainSaga中使用yield all()会等待所有传入的saga任务执行完毕,因此在all()之后添加的逻辑,会在所有pollSaga实例完成后触发:
function* mainSaga() { // 等待所有pollSaga实例执行完成 yield all( someArrayOfIds.map((id) => call(pollSaga, id)) ) // 所有实例完成后执行这里的逻辑,比如分发全局完成动作 yield put({ type: 'ALL_POLL_SAGAS_FINISHED' }) }
可选:主动取消指定实例(无需分发动作)
如果需要在saga内部主动取消某个实例,可以通过fork创建任务并保存引用,再用cancel effect直接终止:
function* mainSaga() { // 存储每个id对应的任务引用 const taskMap = {} // 用fork创建任务,而非call(call会阻塞,但all仍会等待所有fork任务完成) yield all( someArrayOfIds.map((id) => { const task = yield fork(pollSaga, id) taskMap[id] = task return task }) ) // 示例:主动取消id为"123"的实例 // yield cancel(taskMap['123']) // 所有任务完成后触发 yield put({ type: 'ALL_POLL_SAGAS_FINISHED' }) }
说明
- 当
pollSaga被race终止时,其内部调用的workSaga会自动被取消——Redux Saga的子saga会随父saga的终止而终止,无需额外处理workSaga的循环。 - 带ID的停止动作确保了信号的唯一性,不会误终止其他实例。
内容的提问来源于stack exchange,提问作者underfrankenwood
相关产品推荐
相关产品推荐

