[OMT] Next.js와 비동기
2023.11.07(화)
취업준비와 여행등으로 인해 오랜만에 글을 다시 남겨본다 그간 조금씩 시간날 때 마다 프로젝트를 진행했었다.
오늘 남기고 싶은 내용은 Next.js에서 axios를 통해 받아온 정보가 나타나지 않는걸 해결해보고자 함이다.
우선 데이터를 받아오는 순서와 페이지가 로딩되는 순서에 차이가 발생해서 생기는 이슈인 것 같다.
현재의 문제점
Detail Page에서는 잘 받아오는 포스터 URL이 Home과 selectMovie 페이지에서는 반응하지 않는다
이게 어느날은 모두 동작이 잘 되고 어느날엔 못받아오고 이러다 보니 아예 해결하기 위해 많은 고뇌의 시간을 거쳤다..
잘 되지 않는 날의 페이지들
- DetailPage ( 항상 정보를 잘 받아오는 중 )
-
Home
-
selectMovie
Home과 selectMovie 페이지는 코드를 서로 공유하고 있다보니 동시에 불러오지 못하고 있다.
각 Code
Detail.tsx
const Result = () => {
const [movieData, setMovieData] = useState<MovieState>(initialState);
const [SearchText, setSearchText] = useState('');
const handelDetail = (id: string) => {
localStorage.setItem('MovieNum', id);
};
useEffect(() => {
const storedSearchText = localStorage.getItem('검색어');
if (storedSearchText) {
setSearchText(storedSearchText);
axios
.get(`${KMDB_URL}`, {
params: {
collection: 'kmdb_new2',
detail: 'Y',
title: storedSearchText,
ServiceKey: KMDB_KEY
}
})
.then((res) => {
const results: MovieData[] = res.data.Data[0]?.Result || [];
const processedData: MovieState = {
moviePosters: results.map((result) => result.posters.split('|')[0]),
movieTitle: results.map((result) =>
result.title.replace(/!HS|!HE/g, '')
),
movieId: results.map((result) => result.movieId),
movieSeq: results.map((result) => result.movieSeq),
rating: results.map((result) => result.rating),
genre: results.map((result) => result.genre),
runtime: results.map((result) => result.runtime)
};
setMovieData(processedData);
})
.catch((error) => {
console.error('Error fetching data:', error);
});
}
}, []);
...
항상 동작이 잘되고 있는 Detail page 코드이다.
Home
const Chart = () => {
const [movieChart, setMovieChart] = useState<DailyBoxOfficeItem[]>([]);
const [moviePosters, setMoviePosters] = useState<string[]>([]);
// 무비차트 데이터 받아오기
useEffect(() => {
axios
.get(`${URL}`, {
params: {
key: `${KEY}`,
targetDt: `${date}`
}
})
.then((res) => {
let result = res.data.boxOfficeResult;
let extractedData = result.dailyBoxOfficeList.map(
(item: DailyBoxOfficeItem) => ({
rank: item.rank,
movieNm: item.movieNm,
audiAcc: item.audiAcc
})
);
setMovieChart(extractedData);
// 영화 postURL 받아오기
const detailMovieInfo = extractedData.map((movie: any) => {
return axios.get(`${KMDB_URL}`, {
params: {
collection: 'kmdb_new2',
detail: 'Y',
title: movie.movieNm,
ServiceKey: `${KMDB_KEY}`,
releaseDts: 2023
}
});
});
Promise.all(detailMovieInfo)
.then((responses) => {
const posters = responses.map((res) => {
const data = res.data.Data[0].Result[0];
// console.log(data.posters.split('|')[0]);
if (data && data.posters) {
const posters = data.posters;
const posterArray = posters.split('|');
if (posterArray.length > 0) {
return posterArray[0];
}
}
});
setMoviePosters(posters);
})
.catch((error) => console.log(error));
})
.catch((error) => console.log(error));
}, []);
영화진흥회에서 1위에서 10위까지의 영화 정보를 받아와 그 영화 제목들을 바탕으로 KMDB에서 포스터 URL을 받아오는 식으로 코드를 짰다.
맨 처음에 짠 코드에서는 종종 되는 것도 아닌 아예 적용이 안되었다 그 이유는 영화정보를 가져오는 비동기 작업이 완료되기 전에 내가 사용하는 slider 컴포넌트가 먼저 렌더링 되기 때문이였다. 그래서 Promise.all을 사용하여 Poster정보를 받아올때까지 기다린 후에 슬라이더 컴포넌트가 렌더링되도록 했었다.
해결
가장 처음에 말한 Promise.all에 집중을 해보았고 위 코드에서는 poster에 대한 부분만 적용을 하였는데 영화 정보 전체를 포함시켰다.
Home ( 수정 코드 )
useEffect(() => {
axios
.get(`${URL}`, {
params: {
key: `${KEY}`,
targetDt: `${date}`
}
})
.then((res) => {
let result = res.data.boxOfficeResult;
let extractedData = result.dailyBoxOfficeList.map(
(item: DailyBoxOfficeItem) => ({
rank: item.rank,
movieNm: item.movieNm,
audiAcc: item.audiAcc
})
);
// 영화 포스터 URL 받아오기
const detailMovieInfoPromises = extractedData.map((movie: any) => {
return axios
.get(`${KMDB_URL}`, {
params: {
collection: 'kmdb_new2',
detail: 'Y',
title: movie.movieNm,
ServiceKey: `${KMDB_KEY}`,
releaseDts: 2023
}
})
.then((res) => {
const results = res.data.Data[0]?.Result || [];
const posters = results.map(
(result: any) => result.posters.split('|')[0]
);
return posters[0] || '/png/preparing.png';
})
.catch((error) => {
console.error('에러 내용', error);
return '/png/preparing.png';
});
});
Promise.all(detailMovieInfoPromises)
.then((posters) => {
setMoviePosters(posters);
setMovieChart(extractedData); // 영화 정보 및 포스터 정보가 모두 준비된 후에 상태를 업데이트
})
.catch((error) => {
console.error('에러 내용', error);
setMoviePosters([]);
setMovieChart([]); // 포스터 정보를 가져오지 못할 경우 빈 배열로
});
})
.catch((error) => {
console.error('에러 내용', error);
setMovieChart([]);
setMoviePosters([]);
});
}, []); // 빈 의존성 배열을 사용하여 한 번만 실행되도록 하기
해결사진
분명 내 코드에는 오류가 많았었는데 되는날은 왜 되었던 건지는 아직 잘 모르겠어서 좀 더 알아봐야 할 것 같다. 처음에 안될 때는 요청 개수를 초과했다고 생각했는데 detail 페이지를 만들면서 그게 아닌것을 알게되었고 그래서 순서 정리의 문제라는 것을 깨닫게되었다. 아직 해결해야 할 오류들이 많이 있는데 초기부터 생겼던 오류를 해결할 수 있게 되어 굉장히 기쁘다.