반응형

프론트엔드 성능 최적화를 하다 보면 “렌더링 비용을 줄인다”는 말을 자주 듣습니다. 그런데 여기서 말하는 렌더링이 항상 같은 의미는 아닙니다.

React에서 말하는 렌더링 비용과 브라우저가 실제 화면을 그리는 렌더링 비용은 서로 다른 계층의 문제입니다. 이 둘을 구분하지 못하면 최적화 방향이 쉽게 빗나갑니다.

예를 들어 React Profiler에서 특정 컴포넌트가 불필요하게 자주 렌더링되는 상황인데 CSS 속성만 조정하거나, 반대로 레이아웃 계산이 병목인데 React.memo만 붙이는 식의 실수가 생길 수 있습니다.

React 렌더링 비용이란?

React 렌더링 비용은 컴포넌트 트리 안에서 발생하는 비용입니다.

상태나 props가 바뀌면 React는 어떤 컴포넌트를 다시 계산해야 하는지 판단하고, 컴포넌트 함수를 실행한 뒤 이전 결과와 비교합니다. 이 과정에서 불필요한 계산이나 재렌더가 많아지면 앱이 느려질 수 있습니다.

이때 사용하는 대표적인 도구는 다음과 같습니다.

  • React.memo: props가 바뀌지 않은 컴포넌트의 재렌더를 건너뜁니다.
  • useMemo: 비용이 큰 계산 결과를 의존성 기준으로 캐싱합니다.
  • useCallback: 함수 참조를 안정화해 memoized child의 불필요한 렌더를 줄입니다.
  • useDeferredValue, startTransition: 급하지 않은 UI 업데이트의 우선순위를 낮춥니다.
  • 리스트 가상화: react-window, react-virtualized처럼 화면에 보이는 항목만 렌더링합니다.
  • React DevTools Profiler: 어떤 컴포넌트가 왜, 얼마나 오래 렌더링됐는지 측정합니다.

즉 React 최적화의 핵심 질문은 이것입니다.

컴포넌트가 불필요하게 많이 다시 계산되고 있는가?

브라우저 렌더링 비용이란?

브라우저 렌더링 비용은 DOM과 CSS가 실제 픽셀로 바뀌는 과정에서 발생하는 비용입니다.

브라우저는 DOM을 만들고, CSS를 적용하고, 레이아웃을 계산하고, 페인트한 뒤, 필요한 경우 컴포지팅 과정을 거쳐 화면을 보여줍니다. 이 과정에서 레이아웃 계산이나 페인트가 자주 발생하면 사용자는 스크롤 끊김, 애니메이션 버벅임, 화면 흔들림을 체감하게 됩니다.

브라우저 렌더링 비용을 줄이는 도구는 React 최적화 도구와 다릅니다.

  • content-visibility: auto: 화면 밖 콘텐츠의 렌더링 작업을 필요할 때까지 미룹니다.
  • contain: 요소 내부 변화가 바깥 레이아웃과 페인트에 미치는 영향을 제한합니다.
  • contain-intrinsic-size: 아직 렌더링하지 않은 콘텐츠의 예상 크기를 예약합니다.
  • transform, opacity: 레이아웃 재계산 없이 컴포지팅 중심으로 처리하기 쉬운 애니메이션 속성입니다.
  • will-change: 곧 바뀔 속성을 브라우저에 힌트로 알려 최적화 준비를 돕습니다.
  • Chrome DevTools Performance: 레이아웃, 페인트, 스크립트 비용이 어디서 발생하는지 추적합니다.
DOM이 실제 화면으로 그려지는 과정에서 레이아웃, 페인트, 컴포지팅 비용이 큰가?

content-visibility를 쓸 때 주의할 점

content-visibility: auto는 화면 밖 콘텐츠의 렌더링을 미룰 수 있게 해주는 유용한 CSS 속성입니다. 긴 목록이나 아래쪽에 있는 섹션처럼 처음부터 화면에 보이지 않는 영역에 적용하면 초기 렌더링 비용을 줄이는 데 도움이 됩니다.

하지만 한 가지 문제가 생길 수 있습니다.

브라우저가 아직 화면 밖 콘텐츠의 실제 높이를 계산하지 않았다면 문서 전체의 스크롤 길이를 정확히 알기 어렵습니다. 그러면 사용자가 스크롤해서 해당 콘텐츠에 가까워지는 순간 실제 크기가 확정되면서 스크롤바 위치나 레이아웃이 갑자기 흔들릴 수 있습니다.

그래서 보통 contain-intrinsic-size를 함께 사용합니다.

.article-card-list {
  content-visibility: auto;
  contain-intrinsic-size: 320px;
}

이 코드는 다음과 같은 의미입니다.

아직 실제로 렌더링하지 않았더라도, 이 요소는 대략 320px 높이라고 가정하고 공간을 잡아둔다.

예상 크기를 미리 잡아두면 브라우저가 화면 밖 콘텐츠를 늦게 렌더링하더라도 레이아웃 흔들림을 줄일 수 있습니다.

어떤 최적화를 먼저 해야 할까?

최적화는 도구 이름부터 고르는 일이 아닙니다. 먼저 병목이 어디에 있는지 확인해야 합니다.

React 컴포넌트가 불필요하게 자주 렌더링되고 있다면 React DevTools Profiler로 원인을 확인하고 React.memo, useMemo, useCallback, 리스트 가상화 같은 방법을 검토할 수 있습니다.

반대로 레이아웃 계산, 페인트, 스크롤, 애니메이션이 문제라면 Chrome DevTools Performance 탭에서 브라우저 렌더링 비용을 봐야 합니다. 이때는 content-visibility, contain, transform, opacity 같은 CSS 중심의 최적화가 더 직접적인 해결책이 될 수 있습니다.

결론

React 렌더링 비용과 브라우저 렌더링 비용은 모두 사용자 경험에 영향을 주지만, 문제의 위치가 다릅니다.

React 최적화는 컴포넌트 트리 안에서 불필요한 재계산과 재렌더를 줄이는 일입니다. 브라우저 최적화는 DOM이 실제 픽셀로 바뀌는 과정에서 레이아웃, 페인트, 컴포지팅 비용을 줄이는 일입니다.

실무에서 중요한 것은 “어떤 최적화 기법을 많이 아는가”보다 “지금 느린 원인이 어느 계층에 있는지 구분할 수 있는가”입니다. 원인을 먼저 찾고, 그 계층에 맞는 도구를 선택하는 것이 성능 최적화의 출발점입니다.

반응형