2017-02-16 16 views
2

я борюсь с redux-observable, пытаясь выяснить, как создать эпопею с этим потоком:использования Redux-наблюдаемым эпос декорировать данные через несколько действий

  1. слушать для GET_ITEMS_REQUEST действий
  2. Написать запрос HTTP, чтобы получить некоторые пункты
  3. захватить идентификаторы этих элементов и направить GET_ITEM_DETAILS_REQUEST действия, которое будет отправить еще один запрос HTTP, чтобы получить некоторые дополнительные детали для этих элементов
  4. украшают элементы из первого запроса с ДЭТОЙ ils со второго запроса и отправить окончательное действие GET_ITEMS_SUCCESS, в котором будет обновлено состояние редукции

Переход с шага 3 в 4, где я застрял. Я знаю, как отправить GET_ITEM_DETAILS_REQUEST с идентификаторами элементов, но я не знаю, как прослушать/подписаться на действие GET_ITEM_DETAILS_REQUEST, чтобы получить ответ детали.

До сих пор у меня есть следующие:

function getItemsEpic(action$) { 

    return action$ 
    // step 1 
    .ofType('GET_ITEMS_REQUEST') 
    .mergeMap(() => { 
     // step 2 
     return Observable.from(Api.getItems()) 
    }) 
    .mergeMap((items) => { 
     // step 3 
     const itemIds = items.map((item) => item.id); 
     return Observable.of({ 
     type: 'GET_ITEM_DETAILS_REQUEST', 
     ids: itemIds 
     }); 
    }) 
    // ... what now? 
    .catch(() => { 
     return Observable.of({ 
     type: 'GET_ITEMS_FAILURE' 
     }); 
    }); 
} 

ответ

1

Один подход, после того как вы получили детали, начать прослушивание GET_ITEM_DETAILS_FULFILLED, а затем сразу же стартует GET_ITEM_DETAILS_REQUEST используя startWith(). Другой эпик будет смотреть детали вверх и испускать GET_ITEM_DETAILS_FULFILLED, которые наш новый эпос терпеливо ждет, а затем застегнет два (предметы + детали) вместе.

const getItemDetailsEpic = action$ => 
    action$ 
    .ofType('GET_ITEM_DETAILS_REQUEST') 
    .mergeMap(({ ids }) => 
     Observable.from(Api.getItemDetails(ids)) 
     .map(details => ({ 
      type: 'GET_ITEM_DETAILS_FULFILLED', 
      details 
     })) 
    ); 

const getItemsEpic = action$ => 
    action$ 
    .ofType('GET_ITEMS_REQUEST') 
    .mergeMap(() => 
     Observable.from(Api.getItems()) 
     .mergeMap(items => 
      action$.ofType('GET_ITEM_DETAILS_FULFILLED') 
      .take(1) // don't listen forever! IMPORTANT! 
      .map(({ details }) => ({ 
       type: 'GET_ITEMS_SUCCESS', 
       items: items.map((item, i) => ({ 
       ...item, 
       detail: details[i] 
       // or the more "safe" `details.find(detail => detail.id === item.id)` 
       // if your data structure allows. Might not be necessary if the 
       // order is guaranteed to be the same 
       })) 
      })) 
      .startWith({ 
       type: 'GET_ITEM_DETAILS_REQUEST', 
       ids: items.map(item => item.id) 
      }) 
     ) 
    ); 

Отдельно я заметил, что вы кладете catch() на внешней цепи наблюдаемых. Это, вероятно, не будет делать то, что вы хотите. К тому времени, когда ошибка достигнет верхней цепи, весь ваш эпический будет прекращен - он больше не будет слушать будущее GET_ITEMS_REQUEST! Это очень важное различие, и мы часто называем это «изолированием ваших наблюдаемых цепей». Вы не хотите, чтобы ошибки распространялись дальше, чем нужно.

// GOOD 
const somethingEpic = action$ => 
    action$.ofType('SOMETHING') 
    .mergeMap(() => 
     somethingThatMayFail() 
     .catch(e => Observable.of({ 
      type: 'STUFF_BROKE_YO', 
      payload: e, 
      error: true 
     })) 
    ); 

// NOT THE SAME THING! 
const somethingEpic = action$ => 
    action$.ofType('SOMETHING') 
    .mergeMap(() => 
     somethingThatMayFail() 
    ) 
    .catch(e => Observable.of({ 
     type: 'STUFF_BROKE_YO', 
     payload: e, 
     error: true 
    })); 

Иногда вы действительно хотите поймать на внешней цепи, но это последняя вещь, канавы обычно только на наличие ошибок, которые не восстанавливаются.

+0

Я сделал важное изменение: я забыл добавить 'take (1)' после 'action $ .ofType ('GET_ITEM_DETAILS_FULFILLED')'. Это важно, потому что иначе ваш эпический навсегда будет их слушать, а с помощью 'mergeMap' будет бесконечно накапливаться все больше и больше. – jayphelps

+0

Это выглядит великолепно, спасибо! Какие гарантии того, что 'GET_ITEM_DETAILS_FULFILLED' будет точно ответом на запрошенный запрос данных, который был немедленно отправлен? Что делать, если есть еще один «GET_ITEM_DETAILS_FULFILLED», который был отправлен до того, как запрос на получение информации вернется с ответом? – Hristo

+0

Кстати, спасибо за заметку о 'catch()'. Я тоже борется с этим. – Hristo

 Смежные вопросы

  • Нет связанных вопросов^_^