export const getData = async () => {
const res = await fetch("https://jsonplaceholder.typicode.com/posts");
const data = await res.json();
const firstData = data.slice(0, 20);
return firstData;
};
// getData.js
useEffect(() => {
const rawData = getData();
setData(rawData);
}, []);
//App.js
다음 코드는 잘 실행이 될까?
.
.
.
.
.
.
.
.
.
.
.
.
.
.
정답은 X!!
const getData = async () => {
const res = await fetch("https://jsonplaceholder.typicode.com/posts");
const data = await res.json();
const firstData = await data.slice(0, 20);
return firstData;
};
이 코드만 놓고 봐서는 실행이 잘 될 것이다.
비동기처리를 위해 부모 함수에 async를 걸고,
데이터가 잘 받아와질 때까지 await를 통해 코드 진행을 멈춘 뒤,
firstData를 반환한다.
하지만 이것을 moudule로 불러와서 함수를 call하는 경우엔 또 다르다.
useEffect(() => {
const rawData = getData();
setData(rawData);
}, []);
//App.js
여기서 getData()는 promise 객체를 반환받게 된다. 왜냐면 콜백 함수가 async이기 때문이다.
promise 객체는 크게 pending(대기), fulfilled(성공), rejected(거절) 이렇게 세개의 상태가 있다.
그러므로 그냥 getData() 함수를 호출만 한다면 pending 상태의 promise 객체만 받아올 것이다.
그러므로 then() 메소드를 이용해 기다리거나, await 를 다시 사용해 getData에게서 온전히 fulfilled 될 때까지 기다려야 한다.
그렇다고 해서 useEffect에 async를 걸어줄 수는 없다.
useEffect( async () => {
const rawData = await getData();
setData(rawData);
}, []);
//App.js
//사실 이게 젤 깔끔해보이긴 하는데...
왜냐면 useEffect는 단순 함수을 내보내기에, 그 이외에 promise 등을 반환하는 부수효과를 가진 함수를 넣을 수 없다. 그러므로 다음과 같은 형식이 요구된다.
useEffect(() => {
const getRawData = async () => {
const rawData = await getData();
setData(rawData);
}
getRawData();
}, []);
//App.js
사실상 프로미스 객체를 2번 만들게 되는 번거러움이 있지만...(getData.js에서 한 번, app.js에서 불러올 때 한 번..)
data를 받아오는 로직을 분리하기 위해서, 그리고 asnyc와 await를 사용하지 않으면 데이터를 가져오는데 부하가 걸리기 때문에 어쩔 수 없을 것이다...
더 괜찮은 방법이 있을까...?