고객이 취소 요청과 함께 이미지를 여러장 첨부했을때 생기는 이미지 리스트에
Lazy Loading을 사용해보기로 했다.
Lazy Loading은 지금 안보이는 영역에 있는 데이터는
유저가 볼때쯤 되어서야 나중에 가져오는 것이다.
앞선 결제관리 리스트의 Virtual List에서는 교차 부분을 직접 계산했다면
여기서는 Intersection Observer API를 사용해보았다.
WEB DEV DAB의
[Lazy Loading Images with IntersectionObserver and React Hooks]
구현에는 이 글이 정말 도움이 많이 되었다.
영어긴 하지만 기본 원리에 대해 깔끔하게 정리가 되어있다.
이해가 어려웠던 두가지 포인트는
였다. 다 구현하고 난 지금은 이해가 되지만 처음 볼때에는 이것 참 복잡하기 그지없었다ㅠㅠ
observer의 뿌리는 이미지 리스트 전체를 감싸는 상위 컴포넌트에 있고
ref는 그 박스를 지나가는 각각의 이미지에 걸어준다.
(나는 분명 figma에서 "flower"라고 검색했는데 저 빨간 그림이 나왔다..)
(앞뒤생략)
return (
<RequestImgBox onClick={handleRequestImgClick}>
<img ref={imageEl} data-src={src} src={noImage} alt={alt}></img>
</RequestImgBox>
);
👉 CustomerCancelRequest.tsx 전체 보기
여기서 또 생소했던 것이 data-src
였다.
HTML5 특정 요소와 연관되어 있지만 확정된 의미는 갖지 않는 데이터에 대한 확장 가능성을 염두에 두고 디자인되었습니다. data-* 속성은 표준이 아닌 속성이나 추가적인 DOM 속성, Node.setUserData()과 같은 다른 조작을 하지 않고도, 의미론적 표준 HTML 요소에 추가 정보를 저장할 수 있도록 해줍니다.
(* 출처: MDN의 [데이터 속성 사용하기])
추가 정보를 해당 요소의 dataset이라는 임시 속성에 저장해두는 것으로 이해했다.
그래서 Lazy Loading에서는
1.
기본값으로 src에는 No Image를, data-src에는 실제 이미지 값을 넣고,
2.
해당 이미지가 범위 안에 들어오면 "data-src"에 있던 값을 "src"에 할당해둔다. (entry.isIntersecting = true)
3.
"data-src" 속성은 더이상 필요가 없으니 삭제하고, 해당 이미지에 대한 관찰도 중지(unobserve)한다.
const onImageInView: IntersectionObserverCallback = (entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const element = entry.target;
const imageSrc = element.getAttribute("data-src");
if (!imageSrc) return;
element.removeAttribute("data-src");
element.setAttribute("src", imageSrc);
observer.unobserve(element);
}
});
};
차근차근 따라해보니 Lazy Loading은
이해가 안됐던 초반의 걱정에 비해 구현이 잘 되었다.
근데 또 여기서 맞닥뜨린 문제는
이미지 리스트가 가로로 나열되어있고 overflow: auto
가 되어있는데
넘쳐서 안보이는 부분을 보려면 shift+스크롤을 해야만 옆으로 넘길 수 있다는거...
그래서 이 부분은 스크롤바를 커스텀해서 활용했다.
우선 스크롤바가 항상 보여야 활용을 할 수 있으니
overflow: scroll
로 수정을 했다.
그리고 가로 스크롤만 생겨야 하니까 overflow-x
로 바꿔주었다.
그리고 "이게 스크롤바다!"라고 잘 보이도록
크키와 색상을 커스텀 해주었다.
const RequestImgList = styled.div`
padding-bottom: 1.5rem;
display: flex;
overflow-x: scroll;
::-webkit-scrollbar {
height: 1.3rem;
border-radius: 0.4rem;
border: 0.07rem solid var(--borderGray);
}
::-webkit-scrollbar-thumb {
background-color: var(--borderGray);
border-radius: 1rem;
}
`;
여기서 초기 기획에서 생각지 못했던 부분을 찾았다.
레이지로딩이 걸려있는 이 이미지 리스트 각각의 아이템도 확대해서 볼 수 있어야 한다는 점이었다.
그렇게 image carousel을 만들게 되는데...
J4J님의 [지연 로딩(Lazy Loading)으로 최적화하기]
syj9484님의 [React - Intersection Observer API를 이용한 lazy loading]
juno7803님의 [useRef 200% 활용하기]
gtbowurrs님의 [스크롤바 스타일(디자인)하는 방법 - webkit-scrollbar]
EnSSo님의 [Css 브라우저 스크롤바 스타일 지정, 바꾸는 방법 알아보기]