При отмене саг-задачи с помощью ejectSaga yield cancelled () не срабатывает - PullRequest
0 голосов
/ 16 ноября 2018

Я использую функциональность 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() никогда не запускается, несмотря на то, что задача была успешно отменена. Я что-то упускаю из-за того, как работает отмена саги? Есть ли простой способ для меня легко обработать логику очистки саги, когда сага собирается быть отменена?

1 Ответ

0 голосов
/ 16 ноября 2018

Я думаю, вы неправильно понимаете, как отмена задачи работает в redux-saga.

  1. Ваша задача, соответствующая watchSizesDraftsSaga(), завершается сама по себе.
  2. Тогда task.cancel() ничего не делает.Блок

yield cancelled() будет выполняться только в том случае, если вы отмените задачу, когда она еще выполняется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...