Как применить Different () к массиву объектов RxJS? - PullRequest
1 голос
/ 07 июня 2019

Я получаю список домашних животных из API чванства домашних животных. Я хочу удалить домашних животных с дублирующимися идентификаторами, а затем отправить их в React, чтобы избежать проблемы с дублирующимся ключом. Я попробовал код ниже, но у меня не работает. Кто-нибудь может мне помочь с этим?

Я новичок в RxJS, поэтому хочу удалить закомментированный код, который фильтрует отдельные объекты на основе идентификатора питомца.

export function fetchPetEpic(action$) {
    return action$.pipe(
        ofType('GET_PETS'),
        switchMap(action => 
            ajax.getJSON(`https://petstore.swagger.io/v2/pet/findByStatus?status=${action.payload}`).pipe(
                map( response => response.map( (pet) => ({
                    id: pet.id,
                    pet: pet.pet
                }))),
                distinct( petList => petList.id),
                // map( petList => petList.filter((pet, index, list) => {
                //                     return list.map(petObj =>
                //                         petObj.id).indexOf(pet.id) === index;
                //                     })),
                map(response => petActions.setPets(response))
        )),
        catchError( error => ({ type: 'ERROR_PETS_FETCH', payload: error})),
    )
}

Предположим, что массив питомцев похож на [ {id: 1, домашнее животное: собака}, {id: 2, домашнее животное: кошка}, {id: 3, домашнее животное: рыба}, {id: 2, домашнее животное: крыса}, {id: 4, домашнее животное: попугай}, {ID: 1, домашнее животное: сова} ]

Ожидаемый результат: [{id: 1, домашнее животное: собака}, {id: 2, домашнее животное: кошка}, {id: 3, домашнее животное: рыба}, {id: 4, домашнее животное: попугай}]

Вывод, который я получаю, совпадает с массивом ввода.

1 Ответ

0 голосов
/ 07 июня 2019

Функция getJSON возвращает наблюдаемое, которое испускает один элемент (ответ) и завершается.(Или он может выдать одну ошибку.) Учитывая ваш счастливый путь возврата массива ...

Следующий оператор map получит десериализованный массив JSON и отобразит его в новый массив.Таким образом, оператор map будет иметь ровно одно входное событие и приведет к ровно одному выходному событию.

map(response => response.map(pet => ({
  id: pet.id,
  name: pet.name,
  status: pet.status,
}))),

Оператор distinct работает с несколькими событиями .Для каждого события он отфильтровывает любые дубликаты (определение дубликатов настраивается, как вы заметили).Следующий оператор distinct всегда будет проходить через ваше одиночное событие.Также обратите внимание, что petList - это массив .Массивы не имеют свойства id, поэтому лямбда возвращает undefined.Однако не имеет значения, что возвращает лямбда.Поскольку существует только одно событие, оно не использует возвращаемое значение ни в каких сравнениях.

distinct(petList => petList.id),

Похоже, вы ожидаете, что distinct обработает каждый элемент массива.Для этого вы можете использовать from для преобразования массива в наблюдаемый и concatMap для генерации каждого элемента по порядку.С несколькими событиями, проходящими через трубу, distinct может творить свою магию:

...
concatMap(from), // shorthand for: `concatMap(response => from(response)),`
map(pet => ({
  id: pet.id,
  name: pet.name,
  status: pet.status,
})),
distinct(pet => pet.id),
...

Однако это изменение приведет к созданию нескольких действий Redux (по одному для каждого отдельного питомца).Мы можем использовать оператор reduce, чтобы накапливать каждого отдельного питомца обратно в один массив перед созданием действия Redux.

...
reduce((pets, pet) => [...pets, pet], []),
map(pets => petActions.setPets(pets)),
...

Давайте соединим все вместе:

export function fetchPetEpic(action$) {
  return action$.pipe(
    ofType('GET_PETS'),
    switchMap(action =>
      ajax.getJSON(`https://petstore.swagger.io/v2/pet/findByStatus?status=${action.payload}`).pipe(
        concatMap(from), // shorthand for: `concatMap(response => from(response)),`
        map(pet => ({
          id: pet.id,
          name: pet.name,
          status: pet.status,
        })),
        distinct(pet => pet.id),
        reduce((pets, pet) => [...pets, pet], []),
        map(pets => petActions.setPets(pets)),
        catchError(error => ({ type: 'ERROR_PETS_FETCH', payload: error })),
      )
    ),
  )
}

И последнее замечание: между примерами, которые вы предоставили, и map, который вы применяете, что-то не так.Если массив выглядит следующим образом:

[{id: 1, pet: dog}, ...

Тогда каждый элемент не имеет nameили status свойства, просто id и pet свойства.Может быть, подразумевается следующее?

map(item => ({
  id: item.id,
  name: item.pet.name,
  status: item.pet.status,
})),

Или, может быть, это просто проблема с данными примера, которые вы предоставили.В любом случае, я бы рекомендовал дважды проверить карту, чтобы убедиться, что она проецирует ваши значения, как ожидалось.

...