Функция 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,
})),
Или, может быть, это просто проблема с данными примера, которые вы предоставили.В любом случае, я бы рекомендовал дважды проверить карту, чтобы убедиться, что она проецирует ваши значения, как ожидалось.