Во-первых, много реквизита для этой замечательной библиотеки! Я все еще борюсь с вариантом использования. Я хотел бы сначала вызвать другой эпик и дождаться его завершения, прежде чем продолжить текущий эпик. Допустим, у меня есть форма, в которой пользователь может что-то изменить. Перед загрузкой других данных в форму я хочу сначала сохранить текущие изменения. Есть мысли по этому поводу?
Вызов эпиков из других эпиков
Ответы (2)
Звучит так, как будто вы хотите: если один эпик хочет запустить работу другого эпика и дождаться его завершения, прежде чем продолжить.
Один из подходов (с использованием псевдоимен) заключается в том, что при получении начального действия LOAD_OTHER_DATA
вы сразу же начинаете прослушивать одно SAVE_FORM_FULFILLED
, которое сигнализирует о том, что форма была сохранена (мы начнем чуть позже). При получении мы mergeMap
(или switchMap
, в данном случае не имеет значения), что в наш вызов загружаем остальные данные loadOtherDataSomehow()
и занимаемся обычным делом. Наконец, хитрость, позволяющая начать фактическое сохранение формы, которую мы ожидаем, заключается в добавлении startWith()
в конце всей этой цепочки, которая будет генерировать и отправлять действие для фактического сохранения формы.
const saveFormEpic = (action$, store) =>
action$
.ofType('SAVE_FORM')
.switchMap(() =>
saveFormSomeHow(store.getState().formDataSomewhere)
.map(details => ({
type: 'SAVE_FORM_FULFILLED'
}))
);
const loadOtherDataEpic = action$ =>
action$
.ofType('LOAD_OTHER_DATA')
.switchMap(() =>
action$.ofType('SAVE_FORM_FULFILLED')
.take(1) // don't listen forever! IMPORTANT!
.mergeMap(() =>
loadOtherDataSomeHow()
.map(otherData => ({
type: 'LOAD_OTHER_DATA_FULFILLED',
payload: otherData
}))
)
.startWith({
type: 'SAVE_FORM'
})
);
Вы не упомянули, как работает ваша загрузка и сохранение, так что это просто псевдокод, который вам нужно изменить для вашего варианта использования.
@jayphelps, я просто хотел сказать спасибо за все вопросы, на которые вы ответили, они действительно помогли мне решить многие мои проблемы.
Я пытался сформулировать свой вопрос и обнаружил, что вы уже ответили на него здесь и сумели использовать свой образец для решения моей проблемы.
В моем примере есть/было 2 expics, которые я хочу/редактор вызывать друг после друга:
const requestNameEpic = action$ =>
action$.ofType("REQUEST_NAME")
.switchMap(({id}) =>
Observable.of(`name returned by 'ajax' call, using id: ${id}`) // Ajax simulation
.delay(1000)
.map(name => ({type: "LOAD_NAME", name}))
);
const requestAgeEpic = action$ =>
action$.ofType("REQUEST_AGE")
.switchMap(({name}) =>
Observable.of(`age returned by 'ajax' call, using name: [${name}]`)
.delay(1000)
.map(age => ({type: "LOAD_AGE", age}))
);
Как мне удалось решить это, используя:
const requestDetailsEpic = action$ =>
action$.ofType("LOAD_NAME")
.map(({name}) => ({type: "REQUEST_AGE", name}));
Таким образом, отправка REQUEST_NAME также отправит REQUEST_AGE, но тогда я никогда не смогу отправить только LOAD_NAME.
Я реорганизовал ваш образец, чтобы получить:
const requestDetailsEpic = action$ =>
action$.ofType("REQUEST_DETAILS")
.switchMap(({id}) =>
action$.ofType("LOAD_NAME")
.take(1) // don't listen forever! IMPORTANT!
.map(({name}) => ({type: "REQUEST_AGE", name}))
.startWith({type: "REQUEST_NAME", id})
);
Еще раз спасибо за всю большую работу, которую вы проделали над redux-observable, и за всю поддержку сообщества.