노션처럼 Resize 최적화하기

0_jin·2022년 10월 12일
0

프로젝트

목록 보기
7/9

내가 지금 진행하고 있는 프로젝트에서

window.innerWidth가 가변적으로 변하는 즉, resize가 발생할때
component의 수가 width에 맞춰서 가변적으로 변해야하는 경우에 대해
어떻게 처리 했는가? 를 기록하기 위해 이 글을 작성했다.


ref 사용하기

ref를 사용하여 dom 객체를 꺼내와서 getBoundingClientRect를 사용하여 width값을 가지고 올까 했는데, 애초에 item이 10개라면 10개 모두 렌더링되어 ref를 사용하여 가져오는 dom에는 10개의 item이 렌더링되어 width값이 길어져 길어진 값을 가져올 것이라 판단하였다.

즉, getBoundingClientRect를 사용하여 얻은 width 크기는 모든 item이 렌더링된 크기 일거라 생각하였다.


window.onresize 이용하기

이전에, 노션페이지는 width크기가 가변적으로 변경되면 멈출때 딱 한번 resize가 되어서 알아본적이 있는데, window.onresize를 이용했다고 한다.

따라서, 노션은 window.onresize를 이용하여 리플로우를 방지하였는데, 나도 이것을 한번 사용해보고 싶다고 생각만 했었는데, 드디어 사용해보게 되엇다!!


사용법

첫번째,

// getItemsOfList 는 전체 list에서 갯수를 입력해주면 그 만큼의 아이템을 가져오는 함수이다.

...

const [items,setItems] = useState(getItemsOfList(totalItems,window.innerWidth / SIZE));

window.onresize = () => {
 setItems(getItemsOfList(totalItems,window.innerWidth / SIZE))
}
...

잘동작한다! 근데 어딘가 이상하다.
초기 렌더링이 나타나질 않는다..!


아차차 useEffect..!

useEffect(() => {
   setItems(getItemsOfList(totalItems,window.innerWidth / SIZE))
},[totalItems])

를 추가해주니 바로 잘 동작한다 ㅎㅎ..

엥? 근데 콘솔창을 보니 ??가 72번 찍혔다.. (onresize발생할때 console.log를 찍었습니다.)


Debounce !

그렇다! Debounce를 구현하여 Resize를 최소화할 예정이다!

debounce 코드는 아래와 같다.

export const debounce = (func: Function, ms: number) => {
  let timeout: ReturnType<typeof setTimeout>;

  return () => {
    if (timeout) clearTimeout(timeout);

    timeout = setTimeout(() => {
      func();
    }, ms);
  };
};

다음은 debounce를 적용한 resize 코드이다!

window.onresize = debounce(() => {
 setItems(getItemsOfList(totalItems,window.innerWidth / SIZE))
},500)

잘 동작한다!


resize는 얼마나 줄었을까??

debounce 적용하기 전

약 16ms (주사율) 마다 resize event가 발생하여 브라우저가 살려달라고 말하는것 같다. ( 사실, 이정도까지는 무리 없는 걸로 안다. )

debounce 적용하기 후

width값의 변경이 멈춰서야 비로소 렌더링이 진행된다!

정확한 기준으로 비교를 하지는 못했지만,
위 이미지를 통해 resize를 멈춰야 reflow가 진행되는 것과 매 16ms 마다 reflow가 발생하는건 차이가 있다는 것을 알 수 있다.


추가

window.onresize는 useEffect로 감싸주세요! cleanUp도 필수입니다!

profile
노력하는개발자

0개의 댓글