최종 코드는 맨 밑에 '덧2' 참고!
조건에 따라 api를 각각 따로 호출하고, 결과값은 합쳐서 state에 저장해야 하는 상황이다. 간단한 문제일 줄 알았는데 .then()
안에 있는 결과값을 어떻게 밖으로 빼고 가공해야 몰라서 한참 헤맸다.
if (조건문1) {
fetch
.get('uri')
.then((res1) => res1) // type : arr
.catch(() => {})
}
if (조건문2) {
fetch
.get('uri')
.then((res2) => res2) // type : arr
.catch(() => {})
}
// 원하는 결과값
setResult([...res1, ...res2]) // 대충 느낌만 반영한 코드
Promise.all()
함수를 통해 single promise로 만들고, 이를 .then()
으로 받으면 2차원 array로 쓸 수 있게 된다.[].concat.apply([], exampleArr)
함수를 사용해서 1차원 배열로 만든다!let aPromise;
let bPromise;
if (조건문1) {
aPromise = fetch
.get('uri')
.then((res1) => res1)
.catch(() => {})
}
if (조건문2) {
bPromise = fetch
.get('uri')
.then((res2) => res2)
.catch(() => {});
}
// .filter() :api 반환값이 null일 경우, promise가 undefined이기 때문에 걸러주어야 한다
return [aPromise, bPromise].filter((promise) => promise);
})
.then((promises) => {
Promise.all(promises)
.then((twoDimenArr) => {
setResult([].concat.apply([], twoDimenArr));
});
}
})
더 간단한 방법이 있을 것 같지만 현재로선 이것이 최선이었습니다...🤗
어쨌든 해결!✨
흐름은 그대로 쓰고, 코드만 리펙토링 해보았다. 불필요한 .then()
이 한 번 줄었다.
let aPromise;
let bPromise;
if (조건문1) {
aPromise = fetch
.get('uri')
.then((res1) => res1)
.catch(() => {})
}
if (조건문2) {
bPromise = fetch
.get('uri')
.then((res2) => res2)
.catch(() => {});
}
return Promise.all([aPromise, bPromise].filter((promise) => promise));
})
.then((twoDepthArr) => {
setResult([].concat.apply([], twoDepthArr));
})
데이터가 null일 때 만들어지는 promise는 위 코드처럼 filter로 걸러낼 수 없다!
Be Careful with Async Functions that Return Booleans
a Promise object is not one of the eight falsy values in JavaScript, so checking its truthiness is pointless: When coerced to a boolean, a Promise is always true.
promise는 false로 치지 않는 타입이므로, 강제로 체크할 경우 무조건 true로 확인된다는 뜻.
그러므로, 데이터가 null로 올 경우를 거르고 싶다면 two depth array로 변환된 다음에 걸러야 유효하다.
let aPromise;
let bPromise;
if (조건문1) {
aPromise = fetch
.get('uri')
.then((res1) => res1)
.catch(() => {})
}
if (조건문2) {
bPromise = fetch
.get('uri')
.then((res2) => res2)
.catch(() => {});
}
return Promise.all([aPromise, bPromise]);
})
.then((twoDepthArr) => {
// 방어 코드
const filterArr = twoDepthArr.filter((item) => Boolean(item));
setResult([].concat.apply([], filterArr));
})
Promise.allSettled([promise1, promise2, ...])를 사용해보세요.
allSettled는 { status, value 또는 reason }을 리턴하는데요. promise가 resolve될 경우 value, reject 될 경우 reason이 됩니다. status는 fulfilled 또는 rejected가 되구요. allSettled를 사용하면 프라미스가 실패할 경우를 조치해줄 수 있어서 편리해요.
그리고 프라미스를 다룰때 많이 쓰이는게 async 함수인데요. 함수를 만들때 async 키워드를 사용하여 비동기 함수로 만들고, 내부에서 await을 이용해서 결과값을 동기적으로 처리할 수 있어요.
아래 간단한 예시를 적어봤어요.
function async combinePromise (promise1, promise2) {
// promise들의 결과를 result에 담고, result를 순회하며 value에 담겨있는 객체(보통 api 결과는 객체형태일 것으로 예상)를 합쳐준다.
const result = await Promise.allSettled([promise1(), promise2()])
return result.reduce((a,b) => ({ ...a.value, ...b.value }))
}
열공하세요! 화이팅~! 💪