[React] 컴포넌트의 크기 측정

ksj0314·2024년 9월 21일
0

React

목록 보기
25/27

컴포넌트가 렌더링된 후 사이즈를 측정하기 위해 useEffect()를 이용해 setSize()를 실행하는 코드가 있습니다.
해당 컴포넌트는 브라우저의 크기가 변동됨에 따라 크기가 변경될 수 있어 window.addEventListener('resize', )를 이용해 다시 사이즈를 측정합니다.

문제점

  1. 매개변수 size
    : setSize()를 실행하는 함수에 매개변수로 size를 넣는 것은 무한루프에 빠질 수 있어 올바르지 않다.
  2. setTimeout()
    : 렌더링 된 후 사이즈 측정의 타이밍이 맞지 않아 사용하였는데 렌더링 속도가 일정하지 않으니 정확한 방법은 아니다.
  3. useEffect()
    : 해당 컴포넌트의 size를 측정하는 이유는 내부에 있는 UI에서 해당 값을 사용하려는 목적이다. 컴포넌트가 그려진 후 사이즈를 측정하고 내부 요소가 해당값을 이용해 크기가 정해진다면 화면이 깜빡이거나 렌더링 후 추가 렌더링이 발생하는 등의 상황이 유발될 수 있어 크기를 측정하는 작업에는 useEffect()가 적절하지 않다.

useLayoutEffect() + requestAnimationFrame()

  1. useLayoutEffect()
    : DOM이 변경된 직후 실행됩니다.
    ※ 레이아웃이나 스타일 계산이 완료되기 전일 수 있습니다.

  2. requestAnimationFrame()
    : 레이아웃과 스타일 계산이 완료된 후 브라우저가 화면을 repaint하기 직전에 실행됩니다. 때문에 정확한 크기 측정이 가능해집니다.

따라서 컴포넌트의 크기를 측정할 때에는
useEffect() 대신 DOM이 변경되고 화면에 그려지기 전에 실행하겠다는 뜻을 가진 useLayoutEffect()를 이용하고
레이아웃과 스타일 계산이 완료된 후에 실행되는 requestAnimationFrame()를 사용하여 정확한 크기 계산을 합니다.

1) transitionend

위 컴포넌트는 transition 속성이 있어 크기 변화에 딜레이가 있습니다.
그렇기 때문에 mainElement.addEventListener('transitionend', )를 사용하였습니다.

만약 transition 속성이 없다면 ResizeObserver()를 사용할 수 있습니다.

ResizeObserver()를 사용하면 요소의 크기가 변경될 때 마다 콜백을 호출합니다.

트랜지션이 진행되는 동안 여러 번 크기 변화가 감지되어 불필요한 상태 업데이트가 발생할 수 있어
mainElement.addEventListener('transitionend', )를 사용하였습니다.

2) requestAnimationFrame()만 사용하면 안될까?

requestAnimationFrame()만 사용해도 repaint 직전에 실행되니까 굳이 useLayoutEffect()를 사용하지 않아도 되지 않을까? 라는 의문이 생겨서 추가 검색을 해보았습니다.

DOM이 준비된 시점을 보장하기 위해 useLayoutEffect()를 같이 사용해주는것이 좋다고 합니다.

0개의 댓글