эпическая цепочка, наблюдаемая с помощью редукции, отправляет повторяющиеся действия

Легенда

action-chain epic = Epic, который возвращает действие «успех» или «сбой» в зависимости от вызова службы. service = Служба HTTP, от HttpModule, Angular2

Цель

Мне нужно отправить данные на сервер. У меня есть действия CREATE, CREATE_SUCCESS и CREATE_FAIL. Моя идея состоит в том, чтобы отправить CREATE при отправке. Затем у меня есть action-chain epic, который запускает service вызов моего сервера и запускает CREATE_SUCCESS или CREATE_FAIL в зависимости от ответа.

Эта проблема

Мой action-chain epic запускает повторяющиеся действия - в обоих случаях он запускает два действия, например: в случае успеха для каждого CREATE он отправляет два CREATE_SUCCESS действия.

Код

 private createAnimalActionChain() {
        return action$ => {
            return action$
                .ofType(AnimalActions.CREATE)
                .switchMap(action => {
                    return this.service
                        .create(action.payload)
                        .map(httpResponse => {
                            let response = httpResponse.json()
                            if (response.success) {
                                return this.actions.createSuccess()
                            }

                            return this.actions.createFail(response.errors)
                        })
                })
        }
    }

Это то, что я сочинил, и по большей части это работает. Если есть лучший подход, я все уши. До недавнего времени отправка нескольких действий не была реальной проблемой, но мне никогда не казалось, что это нормально, поэтому я хотел бы исправить это.

РЕДАКТИРОВАТЬ: я только что обнаружил, что иногда мое приложение отправляет повторяющиеся действия до выполнения любого Epic. Я сейчас пытаюсь понять, почему.

РЕДАКТИРОВАТЬ 2: не обращайте внимания на ИЗМЕНИТЬ. Это был единичный случай, когда событие отправки поднималось до самого верха, и поскольку я назвал свое поле @Output() 'submit', это вызвало отправку двойного действия. Теперь это исправлено и не имеет отношения к описанной выше проблеме Epic. Это все еще сохраняется.

ИЗМЕНИТЬ 3. С помощью @jayphelps мне удалось отследить проблему. Оказывается, мои действия, вызванные из эпической цепочки, сработали дважды. Я не уверен, почему это происходит. Вот мой старый код:

static CREATE = 'CREATE'
static CREATE_SUCCESS = 'CREATE_SUCCESS'
static CREATE_FAIL = 'CREATE_FAIL'
@dispatch()
create = (animal: IAnimal) => ({
    type: AnimalActions.CREATE,
    payload: animal
})
@dispatch()
createSuccess = () => ({
    type: AnimalActions.CREATE_SUCCESS
})
@dispatch()
createFail = (errors: object) => ({
    type: AnimalActions.CREATE_FAIL,
    payload: errors
})

Этот код отправляет CREATE один раз, CREATE_SUCCESS дважды и CREATE_FAIL дважды. Я удалил два последних @dispatch() декоратора:

static CREATE = 'CREATE'
static CREATE_SUCCESS = 'CREATE_SUCCESS'
static CREATE_FAIL = 'CREATE_FAIL'
@dispatch()
create = (animal: IAnimal) => ({
    type: AnimalActions.CREATE,
    payload: animal
})
createSuccess = () => ({
    type: AnimalActions.CREATE_SUCCESS
})
createFail = (errors: object) => ({
    type: AnimalActions.CREATE_FAIL,
    payload: errors
})

Кажется, что этот код работает правильно и запускает только одно действие. Я очень не понимаю, почему это так работает. Согласно документам API, это свойство украшает единственная функция-создатель действия и отправляет ее возвращаемое значение, объект действия. это очень странно, потому что я называю CREATE и CREATE_SUCCESS одинаково. Как работает этот декоратор?

РЕДАКТИРОВАТЬ 4: я сузил поведение до следующего: если я вызываю действие из моего Epic, и это действие украшено @dispatch, оно запускается дважды. Я подозреваю, что Epic, будучи промежуточным программным обеспечением, отправляет полученное действие внутри себя. Проблема возникает, если мне нужно вручную отправить действие из моего компонента контейнера.

Решение

С помощью jayphelps. Спасибо за ваш ответ. Однако мне нравится @dispatch украшение для использования внутри моих компонентов. Пресональное решение, которое я нашел, - это структурирование моей цепочки действий таким образом, чтобы starter-actions (те, которые отправляются изнутри компонента) не отправлялись через Epic. Тогда просто украсьте эти starter-actions цветом @dispatch, и все заработает.


person Alex    schedule 12.08.2017    source источник
comment
Вы имели в виду, что для каждого CREATE действие срабатывает дважды?   -  person eenagy    schedule 12.08.2017
comment
@eenagy Да, я имел в виду именно это. Редактирование для большей наглядности.   -  person Alex    schedule 12.08.2017


Ответы (1)


Предоставленный код в порядке; см. здесь только один CREATE_SUCCESS: https://jsbin.com/tagovok/edit?js,output

Это говорит о том, что проблема заключается в коде, который здесь не указан. Я могу думать о трех ближайших возможностях:

  • Где-то вы каким-то образом отправляете два CREATE действия (используйте redux devtools, чтобы увидеть)
  • this.service.create(action.payload) на самом деле излучает два элемента вместо одного (используйте do, debuggers, или вы даже можете просто добавить .take(1) после него, и если это исправит, вы знаете)
  • Один и тот же эпос добавлен дважды, например combineEpics(yourEpic, yourEpic) (это трудно подтвердить. Может быть, попробуйте добавить счетчик к начальному вызову эпической it и убедиться, что он увеличивается только до 1, поскольку сама эпическая функция вызывается только один раз)

Обновление на основе вашего:

Я сузил поведение до следующего: если я вызываю действие из моего Epic и это действие украшено @dispatch (), оно запускается дважды. Я подозреваю, что Epic, будучи промежуточным программным обеспечением, отправляет полученное действие внутри себя. Проблема возникает, если мне нужно вручную отправить действие из моего компонента контейнера.

Действительно, redux-observable автоматически отправляет действия, создаваемые вашими эпиками. У меня нет опыта использования angular-redux, но есть некоторые документы по его использованию с redux-observable здесь: https://github.com/angular-redux/store/blob/master/articles/epics.md

Беглый беглый обзор показывает, что они не используют создателей действий в эпосах, а вместо этого используют POJO. Вы по-прежнему можете создавать создателей действий, которые возвращают только действия POJO, просто обычное сокращение.

person jayphelps    schedule 12.08.2017
comment
@alex, вы можете попробовать с помощью предоставленной помощи, и если это все еще не решает вашу проблему, я предлагаю вам обновить свой ответ недостающими деталями - person eenagy; 13.08.2017
comment
Спасибо за вклад. Я пробежался по этим мыслям, и единственная потенциальная проблема, которую я обнаружил, - это использование декоратора @dispatch() из angular-redux/store. Я должен отправить дубликаты. Я не зарегистрировал лишних эпиков, я отправляю одно CREATE действие (подтверждено с помощью инструментов Redux dev). Я постараюсь отправить в обычном режиме. - person Alex; 13.08.2017
comment
Рад это слышать! - person jayphelps; 15.08.2017
comment
Я тоже столкнулся с той же проблемой. Моя эпопея дважды отправляет одно и то же действие. Хотя в моем случае это происходит только в моих тестах для эпика. Отладка моего приложения с использованием redux-dev-tools показывает только одно отправленное действие. К вашему сведению, я использую redux store в приложении React. - person besrabasant; 19.02.2018
comment
@jayphelps Можете ли вы помочь мне с моей проблемой? Почему я получаю два повторяющихся действия? Могу ли я создать отдельный вопрос для этой проблемы? - person besrabasant; 19.02.2018
comment
@besrabasant, у вас есть вопрос о переполнении стека? - person jayphelps; 19.02.2018
comment
@jayphelps Нет, но я решил проблему. Похоже, для этого возникла проблема с GitHub, которую я не смог найти. И я получил решение из вашего комментария по этой проблеме. github.com/redux-observable/redux-observable/issues/ - person besrabasant; 20.02.2018