useQuery로 영화 정보를 가져오는데 불러올 이미지들이 많다보니 제각각 다른 속도로 화면에 나타나는 게 문제였다.
아.. 너무 고생했다.
function Search() {
const offset = 5;
const location = useLocation();
const keyword = new URLSearchParams(location.search).get('keyword');
const { data, isLoading, isError } = useQuery<IGetMovieResult>(
['search', keyword],
() => GetSearched(keyword || '')
);
return (
<Wrapper>
<Row offset={offset}>
{data?.results.map((movie) => (
<Box
offset={offset}
key={movie.id}
variants={boxVariants}
initial="normal"
whileHover="hover"
transition={{ type: 'tween' }}
>
<img
src={
movie.poster_path
? makeImagePath(movie.poster_path, 'w300')
: require('../assets/no-image-icon-6.png')
}
alt={movie.title}
/>
</Box>
))}
</Row>
</Wrapper>
);
}
function Search() {
const offset = 5;
const location = useLocation();
const keyword = new URLSearchParams(location.search).get('keyword');
const { data, isLoading, isError } = useQuery<IGetMovieResult>(
['search', keyword],
() => GetSearched(keyword || '')
);
const [loadedImagesCount, setLoadedImagesCount] = useState(0);
useEffect(() => {
if (data) {
setLoadedImagesCount(0);
const images = data.results.map((movie) => {
const img = new Image();
img.src = movie.poster_path
? makeImagePath(movie.poster_path, 'w300')
: require('../assets/no-image-icon-6.png');
img.onload = () => {
setLoadedImagesCount((prevCount) => prevCount + 1);
};
return img;
});
return () => {
images.forEach((img) => img.onload = null);
};
}
}, [data]);
const isAllImagesLoaded = loadedImagesCount === data?.results.length;
console.log(isAllImagesLoaded);
return (
<Wrapper>
{isAllImagesLoaded && (
<Row offset={offset}>
{data?.results.map((movie) => (
<Box
offset={offset}
key={movie.id}
variants={boxVariants}
initial="normal"
whileHover="hover"
transition={{ type: 'tween' }}
>
<img
src={
movie.poster_path
? makeImagePath(movie.poster_path, 'w300')
: require('../assets/no-image-icon-6.png')
}
alt={movie.title}
/>
</Box>
))}
</Row>
)}
</Wrapper>
);
}
이미지 로드가 완료되었는지 추적할 수 있는 state를 만들고, 모든 이미지가 로드된 것을 확인한 후 렌더링 하도록 했다.
검색 결과를 가져오면 useEffect 훅에서 각 영화 포스터의 URL을 생성하고, 새 Image 인스턴스를 만들어 각 URL을 할당한 후, 이미지가 로드 될 때마다 useState 훅으로 loadedImagesCount를 증가시킨다. loadedImagesCount가 데이터의 결과 수와 일치하는 경우, 모든 이미지가 로드되었다는 뜻. 이때 isAllImagesLoaded를 true로 설정하고 이미지를 렌더링한다.