使用 ejectSaga 取消 saga 任务时,不会触发 yield cancelled()
When cancelling a saga task with ejectSaga, yield cancelled() isn't triggering
我正在使用 react-boilerplate
injectSaga/ejectSaga 功能 (reference),但我 运行 在尝试取消我的 saga 时遇到了问题。
tl;dr - 当注入传奇的组件被卸载时,传奇取消通过 task.cancel() 发生,但这不会在实际传奇本身中触发(即, yield cancelled()
未触发)
我像这样将我的 saga 注入到我的容器中(使用 react-router v4 和 redux):
const enhance = compose(
withRouter, // from react-router 4
injectSaga({ key: 'stuffDirectory', saga: stuffDirectorySaga }),
connect(mapStateToProps, mapDispatchToProps),
// other things that we're composing
);
injectSaga
函数执行以下魔法:
export default ({ key, saga, mode }) => WrappedComponent => {
class InjectSaga extends React.Component {
static WrappedComponent = WrappedComponent;
static contextTypes = {
store: PropTypes.object.isRequired,
};
static displayName = `withSaga(${WrappedComponent.displayName ||
WrappedComponent.name ||
'Component'})`;
componentWillMount() {
const { injectSaga } = this.injectors;
injectSaga(key, { saga, mode }, this.props);
}
componentWillUnmount() {
const { ejectSaga } = this.injectors;
ejectSaga(key);
}
injectors = getInjectors(this.context.store);
render() {
return <WrappedComponent {...this.props} />;
}
}
return hoistNonReactStatics(InjectSaga, WrappedComponent);
};
这是我的故事(非常简单):
export function* watchSizesDraftsSaga() {
try {
let stuffWeLookingFor = yield select(selectStuff());
// waiting for stuff here
yield put( moveStuffOver(stuffWeLookingFor) );
// everything works fine here, page works as expected and stuff has been found
} finally {
if (yield cancelled()) {
// PROBLEM: when the saga is ejected via ejectSaga, this condition never happens
yield put( cleanStuffUp() );
}
}
}
saga 注入工作正常 - 每次安装组件时,我都可以清楚地看到在 redux 中调用和捕获的操作。在 react-boilerplate
的特定 sagaInjectors.js
文件中,我找到了取消注入传奇的特定行:
if (Reflect.has(store.injectedSagas, key)) {
const descriptor = store.injectedSagas[key];
if (descriptor.mode && descriptor.mode !== DAEMON) {
// the task is cancelled here
descriptor.task.cancel();
// we verify that the task is cancelled here - descriptor.task.isCancelled() returns true if we log it
// Clean up in production; in development we need `descriptor.saga` for hot reloading
if (process.env.NODE_ENV === 'production') {
// Need some value to be able to detect `ONCE_TILL_UNMOUNT` sagas in `injectSaga`
store.injectedSagas[key] = 'done'; // eslint-disable-line no-param-reassign
}
}
}
尽管任务已成功取消,但我的 yield cancelled()
块从未 运行。关于 saga 取消的工作原理,我是否遗漏了什么?每当 saga 即将被取消时,有没有一种简单的方法可以让我轻松处理我的 saga 清理逻辑?
我认为你误解了 redux-saga 中任务取消的工作原理。
- 您对应
watchSizesDraftsSaga()
的任务自行完成。
- 然后
task.cancel()
什么也不做。
yield cancelled()
块只有在您取消任务时才会执行,而任务仍然是 运行。
我正在使用 react-boilerplate
injectSaga/ejectSaga 功能 (reference),但我 运行 在尝试取消我的 saga 时遇到了问题。
tl;dr - 当注入传奇的组件被卸载时,传奇取消通过 task.cancel() 发生,但这不会在实际传奇本身中触发(即, yield cancelled()
未触发)
我像这样将我的 saga 注入到我的容器中(使用 react-router v4 和 redux):
const enhance = compose(
withRouter, // from react-router 4
injectSaga({ key: 'stuffDirectory', saga: stuffDirectorySaga }),
connect(mapStateToProps, mapDispatchToProps),
// other things that we're composing
);
injectSaga
函数执行以下魔法:
export default ({ key, saga, mode }) => WrappedComponent => {
class InjectSaga extends React.Component {
static WrappedComponent = WrappedComponent;
static contextTypes = {
store: PropTypes.object.isRequired,
};
static displayName = `withSaga(${WrappedComponent.displayName ||
WrappedComponent.name ||
'Component'})`;
componentWillMount() {
const { injectSaga } = this.injectors;
injectSaga(key, { saga, mode }, this.props);
}
componentWillUnmount() {
const { ejectSaga } = this.injectors;
ejectSaga(key);
}
injectors = getInjectors(this.context.store);
render() {
return <WrappedComponent {...this.props} />;
}
}
return hoistNonReactStatics(InjectSaga, WrappedComponent);
};
这是我的故事(非常简单):
export function* watchSizesDraftsSaga() {
try {
let stuffWeLookingFor = yield select(selectStuff());
// waiting for stuff here
yield put( moveStuffOver(stuffWeLookingFor) );
// everything works fine here, page works as expected and stuff has been found
} finally {
if (yield cancelled()) {
// PROBLEM: when the saga is ejected via ejectSaga, this condition never happens
yield put( cleanStuffUp() );
}
}
}
saga 注入工作正常 - 每次安装组件时,我都可以清楚地看到在 redux 中调用和捕获的操作。在 react-boilerplate
的特定 sagaInjectors.js
文件中,我找到了取消注入传奇的特定行:
if (Reflect.has(store.injectedSagas, key)) {
const descriptor = store.injectedSagas[key];
if (descriptor.mode && descriptor.mode !== DAEMON) {
// the task is cancelled here
descriptor.task.cancel();
// we verify that the task is cancelled here - descriptor.task.isCancelled() returns true if we log it
// Clean up in production; in development we need `descriptor.saga` for hot reloading
if (process.env.NODE_ENV === 'production') {
// Need some value to be able to detect `ONCE_TILL_UNMOUNT` sagas in `injectSaga`
store.injectedSagas[key] = 'done'; // eslint-disable-line no-param-reassign
}
}
}
尽管任务已成功取消,但我的 yield cancelled()
块从未 运行。关于 saga 取消的工作原理,我是否遗漏了什么?每当 saga 即将被取消时,有没有一种简单的方法可以让我轻松处理我的 saga 清理逻辑?
我认为你误解了 redux-saga 中任务取消的工作原理。
- 您对应
watchSizesDraftsSaga()
的任务自行完成。 - 然后
task.cancel()
什么也不做。
yield cancelled()
块只有在您取消任务时才会执行,而任务仍然是 运行。