||Project1|| #9 Lazy Loading (w/ Intersection Observer API)

윤코코·2021년 12월 22일
0

고객이 취소 요청과 함께 이미지를 여러장 첨부했을때 생기는 이미지 리스트에
Lazy Loading을 사용해보기로 했다.

🐌 이미지 Lazy Loading

Lazy Loading은 지금 안보이는 영역에 있는 데이터는
유저가 볼때쯤 되어서야 나중에 가져오는 것이다.

앞선 결제관리 리스트의 Virtual List에서는 교차 부분을 직접 계산했다면
여기서는 Intersection Observer API를 사용해보았다.

WEB DEV DAB의
[Lazy Loading Images with IntersectionObserver and React Hooks]

구현에는 이 글이 정말 도움이 많이 되었다.
영어긴 하지만 기본 원리에 대해 깔끔하게 정리가 되어있다.

이해가 어려웠던 두가지 포인트는

  • ref를 걸어줘야 하는 위치와
  • 이미지를 No Image에서 실제 이미지로 어떻게 바꿔줘야 하는지

였다. 다 구현하고 난 지금은 이해가 되지만 처음 볼때에는 이것 참 복잡하기 그지없었다ㅠㅠ

1. ref를 걸어주는 위치

observer의 뿌리는 이미지 리스트 전체를 감싸는 상위 컴포넌트에 있고
ref는 그 박스를 지나가는 각각의 이미지에 걸어준다.


(나는 분명 figma에서 "flower"라고 검색했는데 저 빨간 그림이 나왔다..)

(앞뒤생략)
    return (
      <RequestImgBox onClick={handleRequestImgClick}>
        <img ref={imageEl} data-src={src} src={noImage} alt={alt}></img>
      </RequestImgBox>
    );

👉 CustomerCancelRequest.tsx 전체 보기

2. 이미지를 No Image에서 실제 이미지로 바꾸는 방법

여기서 또 생소했던 것이 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);
    }
  });
};

👉 useLazyImage.tsx 전체 보기

↔️ 이미지 리스트 가로 스크롤바

차근차근 따라해보니 Lazy Loading은
이해가 안됐던 초반의 걱정에 비해 구현이 잘 되었다.

근데 또 여기서 맞닥뜨린 문제는
이미지 리스트가 가로로 나열되어있고 overflow: auto가 되어있는데
넘쳐서 안보이는 부분을 보려면 shift+스크롤을 해야만 옆으로 넘길 수 있다는거...
그래서 이 부분은 스크롤바를 커스텀해서 활용했다.

1. 스크롤바 항상 보이게 하기

우선 스크롤바가 항상 보여야 활용을 할 수 있으니
overflow: scroll로 수정을 했다.

그리고 가로 스크롤만 생겨야 하니까 overflow-x로 바꿔주었다.

2. 스크롤바 커스텀 하기

그리고 "이게 스크롤바다!"라고 잘 보이도록
크키와 색상을 커스텀 해주었다.

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;
  }
`;

🛠 보완할 점

  • 이미지 리스트 가로 스크롤을 위해서 지금은 스크롤바 커스텀을 했지만, 보완을 한다면 양 옆에 "<", ">" 버튼을 넣어서 좀 더 직관적으로 만드는 게 좋을 것 같다.
  • LazyImage 컴포넌트를 리팩토링 하면 좋을 것 같다. 하지만 디렉토리의 계층을 어떻게 두어야 할지 고민이다...
  • 여기서는 이미지는 최대 10개까지만 업로드할 수 있다고 가정을 했지만, 만약 이미지가 아주 많은 상황이라면? 이미 보고 지나간 이미지라고 영역을 벗어나면 다시 no image로 바꿔주고 observe하는게 용량을 줄일 수 있는 방법일 것 같다.

👣 투비컨티뉴

여기서 초기 기획에서 생각지 못했던 부분을 찾았다.
레이지로딩이 걸려있는 이 이미지 리스트 각각의 아이템도 확대해서 볼 수 있어야 한다는 점이었다.

그렇게 image carousel을 만들게 되는데...

|| 참고 ||

J4J님의 [지연 로딩(Lazy Loading)으로 최적화하기]
syj9484님의 [React - Intersection Observer API를 이용한 lazy loading]
juno7803님의 [useRef 200% 활용하기]
gtbowurrs님의 [스크롤바 스타일(디자인)하는 방법 - webkit-scrollbar]
EnSSo님의 [Css 브라우저 스크롤바 스타일 지정, 바꾸는 방법 알아보기]

profile
Web Front-End Developer

0개의 댓글