Я использую функциональность react-boilerplate
injectSaga / ejectSaga ( ссылка ) и сталкиваюсь с проблемой, пытающейся отменить мою сагу.
tl; dr - Когда компонент с внедренной сагой отключен, отмена саги происходит через task.cancel (), но в самой саге это не срабатывает (т. Е. yield cancelled()
не запуск)
Я внедряю свою сагу в свой контейнер следующим образом (с использованием response-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() );
}
}
}
Внедрение саги работает правильно - каждый раз, когда компонент монтируется, я четко вижу действия, вызываемые и перехватываемые в избыточном количестве. В конкретном файле sagaInjectors.js
из react-boilerplate
я нашел строку, которая отменяет введенные саги:
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()
никогда не запускается, несмотря на то, что задача была успешно отменена. Я что-то упускаю из-за того, как работает отмена саги? Есть ли простой способ для меня легко обработать логику очистки саги, когда сага собирается быть отменена?