이미지 로딩 경험 개선하기

스탁벅스·2023년 7월 9일
2
post-thumbnail
post-custom-banner

최근에 외부 이미지 url을 통해 이미지 가져올 일이 있었는데 끔찍한 일이 벌어졌다.

⚠️ 혐 주의 ⚠️

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

가장 오래걸린 사진은 콘텐츠 다운로드 시간 약 0.8초 포함 1.46초라는 시간이 걸리면서 프론트엔드 개발자로서 도저히 눈뜨고 보기 힘든 처참한 UX를 경험했다.

해결책?

가장 근본적인 해결책은 사진 저장 방식을 바꾸는 것이다. 사진을 압축하거나 저장 방식을 바꾸어 이미지를 작은 용량으로, 최대한 빠르게 가져오는 방식을 생각해야한다. 하지만 그 이전에 프론트엔드 개발자로서 할 수 있는 일들을 생각해봤다. 저장방식을 바꾸어 로딩시간을 지금보다 단축한다고 해도, 만약 사용자 네트워크 상태가 좋지 않으면 결국 비슷한 경험할 수 있는 거 아닌가?

최근들어 Suspense를 이용하여 api 호출 지연시, 따로 만든 로딩 화면을 보여주는 방식으로 사용자 경험을 개선하곤 한다. 모든 컴포넌트가 api 호출을 완료해서 화면이 완전히 준비 될 때까지 다른 컴포넌트로 대체하여 보여주는 방식이다.

(출처: 카카오페이-기술블로그)

비슷한 방식을 이미지에 적용하여 보았다. 한 화면에 담기는 5개의 이미지들이 완전히 로딩이 완료될 때까지 스켈레톤 컴포넌트를 보여주고, 5개의 이미지들이 모두 로딩이 완전히 완료된 뒤에 이미지들이 담긴 컴포넌트를 보여준다.

onLoad

img에는 onLoad 라는 이벤트 속성이 있다. 이미지가 로딩이 완료된 상태를 확인하기 위한 방법이 필요했는데, onLoad 속성을 활용하기로 했다.

도입하기

다섯개의 포스터 이미지를 갖고 있는 Posters 컴포넌트 내부다.

isLoading : 초기에 5개의 true로 채워진 배열이다. 5개의 포스터 이미지들이 로딩중인지 여부를 나타내는 state다.

loadingFinished : 5개의 포스터 이미지들이 모두 로딩이 끝났는지 여부를 나타내는 state다. useEffect를 통해 isLoading을 확인하여 isLoading의 원소가 모두 false면 true가 된다. 불필요하다고도 생각했었지만, 가독성을 위해 만들었다.

loadingFinished가 false 일때, 즉, 아직 모든 이미지들의 로딩이 끝나지 않았을 때 Loading 컴포넌트를 보여준다. 또한 loadingFinished가 false 일때는, 포스터 이미지 하나를 보여주는 컴포넌트인 Poster 컴포넌트가 보이면 안되는데,

만약 위와 같이 코드를 작성하면, loadingFinished의 초기값은 false이므로, Poster 컴포넌트는 렌더링 되지 않고, Poster 컴포넌트가 렌더링 되지 않으니까, 이미지 로딩이 일어나지 않고, loadingFinished의 값이 바뀌지 않아 결과적으로 포스터 이미지들은 평생 보이지 않는다.

위와 같이 loadingFinishedPoster에 props로 넘겨주고, Poster 내부에서 loadingFinished가 false일 때는 'display: none' 처리 하게끔 하여 로딩중일 때 모습을 감추었다.
또한 onLoad 이벤트를 활용해, 로딩이 완료된 Poster는 handleLoad 함수를 통해 isLoading state의 값을 다음과 같이 바꾸었다.

최종 코드

결과

Loading 컴포넌트를 포스터들에 대한 스켈레톤으로 만들고 어설픈 애니메이션도 추가해봤다.

변경 이전과 비교하기 위해 변경 이전을 다시 보자.

.
.
.
.
.
.
.

다시 변경 이후를 보자
.
.
.
.
.
.
.
.
.
.
.

확실히 이전보다 훨씬 보기 좋다. 👏
이미지 로딩이 필요한 다른 페이지들에서도 재사용하기 위해 hooks로 만들어 봐야겠다.

profile
환영합니다. 스탁벅스입니다.
post-custom-banner

2개의 댓글

comment-user-thumbnail
2023년 7월 25일

와 훨씬 보기 편해요(짝짝짝)

1개의 답글