Как заполнить хранилище и последовательно ожидать возврата с помощью Redux Observable?

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

У меня есть эпопея, в которой магазин попадает в магазин FetchTodos. Это прослушивает действие FETCH_TODOS, а затем вызывает мой API задач и заполняет {todos: [] } =

Еще у меня в магазине есть раздел комментариев todoComments. Однако я хотел бы заполнить todoComments только после того, как FETCH_TODOS вернется и заполнит магазин.

В императивном коде это может выглядеть так:

let todos = await api.get('/todos');
await dispatch("FETCH_TODO_COMPLETE", todos)
let firstId = getState().todos[0].id
let comments = await api.get(`/todos/${firstId}/comments')
await dispatch("FETCH_COMMENTS_COMPLETE", { todo_id: firstId, comments})

Ближе всего к этому я обратил внимание на эту проблему в Redux Observable Repo. , но я не мог понять, как это сделать эффективно. Для меня это довольно распространенный сценарий.

Я хотел бы использовать как можно больше кода. В этом примере я могу отправлять FETCH_TODOS из нескольких компонентов.

Как мне добиться этого с помощью Redux-Observable?


person Doug    schedule 27.05.2017    source источник
comment
В вашем примере вы получаете комментарии только к первому заданию в списке let firstId = getState().todos[0].id - это именно то, что вы хотите сделать, или вы хотите получить комментарии к конкретному заданию по идентификатору, или комментарии для всех заданий?   -  person jayphelps    schedule 27.05.2017
comment
Это больше просто показать, что комментарии должны подождать до задач. Ключевой частью является последовательность выборок и доступ к промежуточному состоянию.   -  person Doug    schedule 27.05.2017
comment
Это меняет то, как вы это делаете.   -  person jayphelps    schedule 27.05.2017


Ответы (1)


На основании нашего разговора в комментариях:

В redux-observable вы можете упорядочить вещи множеством способов. Вы можете сделать все это в одном эпике, используя обычный RxJS, или можете разделить их на несколько. Если вы разделите их, последующий эпос будет прислушиваться к сигналу о том, что предыдущий выполнил свою задачу. Что-то вроде этого:

// this assumes you make your `api.get` helper return an Observable
// instead of a Promise which is highly advisable.
// If it doesn't, you could do:
//   Observable.from(api.get('/url'))
// but Promises are not truly cancellable which can cause max
// concurrent connections issues

const fetchTodosEpic = action$ =>
  action$.ofType('FETCH_TODOS')
    .switchMap(() =>
      api.get('/todos')
        .map(todos => ({
          type: 'FETCH_TODOS_COMPLETE',
          todos
        }))
    );

const fetchComments = action$ =>
  action$.ofType('FETCH_TODOS_COMPLETE')
    .switchMap(({ todos }) =>
      api.get(`/todos/${todos[0].id}/comments`)
        .map(comments => ({
          type: 'FETCH_COMMENTS_COMPLETE',
          comments
        }))
    );
person jayphelps    schedule 27.05.2017
comment
Как бы я мог объединить эти 2 эпоса в один эпический призыв? Представьте, что я попал на страницу комментариев, и у меня есть только идентификатор комментария, и мне нужно получить все задачи и все комментарии для рендеринга компонента. То есть было действие под названием FETCH_COMMENT, которое передавало идентификатор комментария, но мне пришлось получить все задачи, а затем все комментарии в моем хранилище redux, чтобы найти этот комментарий. - person Doug; 28.05.2017
comment
Если у вас есть идентификатор комментария, зачем вам ждать чего-то еще? - person jayphelps; 28.05.2017
comment
@jayphelps Как насчет того, чтобы связать 2 действия в цепочку (первое вызывает 4 разных запроса, а другое запускает редуктор, если все 4 запроса выполнены успешно). Возможно ли использование redux-observable? - person petithomme; 10.07.2017
comment
@jayphelps, если вы хотите дать вызывающему эпика контроль над следующим действием (например, onSuccess или onFailure), стоит ли давать эпику действие, содержащее другое действие? Например, эпику ajax может быть дано действие, которое включает действие onSuccess, которое может быть возвращено эпиком, если вызов ajax успешен. - person mikebridge; 17.11.2017
comment
@mikebridge, если действия сериализуемы, это нормально, хотя лично я бы этого не делал. Если цель состоит в том, чтобы уменьшить количество шаблонов, я бы использовал фабрики для создания уникальных эпиков для каждого варианта использования, например createWhateverEpic({ onSuccess: whateverActionCreator, ...etc }). Если вы зададите новый вопрос SO, я буду рад взглянуть. Я наблюдаю за тегом redux-observable - person jayphelps; 17.11.2017
comment
@jayphelps Спасибо --- Я думал о связывании действий с обещаниями, что не похоже на правильную ментальную модель с наблюдаемым сокращением. Я думаю, что могу упростить это, переписав это как серию реакций на изменения состояния редукции. (Хотя эпическая фабрика кажется интересной концепцией.) - person mikebridge; 17.11.2017
comment
@jayphelps, возвращаясь к этой проблеме, если я хочу выполнить что-то вроде обещания, было бы неразумно динамически создать эпик, который прослушивает только одно событие, а затем сам отписывается? - person mikebridge; 19.07.2018